summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuilherme Lepsch <lepsch@expertisesolutions.com.br>2015-07-02 16:50:57 -0300
committerFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2015-10-22 16:23:59 -0200
commitb030e01b2f03b5ef3218dcbf9ecea3d958ac56ea (patch)
tree5d83c37df5b2618bb1ca479655549886cacf7d01
parentb1600b2daa0d5de62b5f738d7845fd512aa6bfba (diff)
downloadefl-b030e01b2f03b5ef3218dcbf9ecea3d958ac56ea.tar.gz
Ecordova eolification and tizen implementation
-rw-r--r--cmakeconfig/EcordovaConfig.cmake.in32
-rw-r--r--cmakeconfig/EcordovaCxxConfig.cmake.in30
-rw-r--r--configure.ac96
-rw-r--r--pc/ecordova-cxx.pc.in12
-rw-r--r--pc/ecordova.pc.in12
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile_Ecordova.am189
-rw-r--r--src/Makefile_Ecordova_Cxx.am22
-rw-r--r--src/lib/ecordova/Ecordova.h50
-rw-r--r--src/lib/ecordova/Ecordova_Common.h13
-rw-r--r--src/lib/ecordova/Ecordova_Eo.h34
-rw-r--r--src/lib/ecordova/ecordova_batterystatus.c196
-rw-r--r--src/lib/ecordova/ecordova_batterystatus.eo51
-rw-r--r--src/lib/ecordova/ecordova_batterystatus_private.h19
-rw-r--r--src/lib/ecordova/ecordova_capture.c60
-rw-r--r--src/lib/ecordova/ecordova_capture.eo178
-rw-r--r--src/lib/ecordova/ecordova_capture_private.h16
-rw-r--r--src/lib/ecordova/ecordova_console.c175
-rw-r--r--src/lib/ecordova/ecordova_console.eo106
-rw-r--r--src/lib/ecordova/ecordova_console_private.h20
-rw-r--r--src/lib/ecordova/ecordova_contact.c1117
-rw-r--r--src/lib/ecordova/ecordova_contact.eo98
-rw-r--r--src/lib/ecordova/ecordova_contact_private.h38
-rw-r--r--src/lib/ecordova/ecordova_contactaddress.c312
-rw-r--r--src/lib/ecordova/ecordova_contactaddress.eo93
-rw-r--r--src/lib/ecordova/ecordova_contactaddress_private.h25
-rw-r--r--src/lib/ecordova/ecordova_contactfield.c415
-rw-r--r--src/lib/ecordova/ecordova_contactfield.eo57
-rw-r--r--src/lib/ecordova/ecordova_contactfield_private.h58
-rw-r--r--src/lib/ecordova/ecordova_contactname.c257
-rw-r--r--src/lib/ecordova/ecordova_contactname.eo58
-rw-r--r--src/lib/ecordova/ecordova_contactname_private.h25
-rw-r--r--src/lib/ecordova/ecordova_contactorganization.c232
-rw-r--r--src/lib/ecordova/ecordova_contactorganization.eo72
-rw-r--r--src/lib/ecordova/ecordova_contactorganization_private.h25
-rw-r--r--src/lib/ecordova/ecordova_contacts.c519
-rw-r--r--src/lib/ecordova/ecordova_contacts.eo76
-rw-r--r--src/lib/ecordova/ecordova_contacts_private.h16
-rw-r--r--src/lib/ecordova/ecordova_contacts_record_utils.c121
-rw-r--r--src/lib/ecordova/ecordova_contacts_record_utils.h20
-rw-r--r--src/lib/ecordova/ecordova_device.c107
-rw-r--r--src/lib/ecordova/ecordova_device.eo60
-rw-r--r--src/lib/ecordova/ecordova_device_private.h20
-rw-r--r--src/lib/ecordova/ecordova_devicemotion.c176
-rw-r--r--src/lib/ecordova/ecordova_devicemotion.eo70
-rw-r--r--src/lib/ecordova/ecordova_devicemotion_private.h20
-rw-r--r--src/lib/ecordova/ecordova_deviceorientation.c180
-rw-r--r--src/lib/ecordova/ecordova_deviceorientation.eo87
-rw-r--r--src/lib/ecordova/ecordova_deviceorientation_private.h20
-rw-r--r--src/lib/ecordova/ecordova_dialogs.c75
-rw-r--r--src/lib/ecordova/ecordova_dialogs.eo87
-rw-r--r--src/lib/ecordova/ecordova_dialogs_private.h16
-rw-r--r--src/lib/ecordova/ecordova_directoryentry.c324
-rw-r--r--src/lib/ecordova/ecordova_directoryentry.eo75
-rw-r--r--src/lib/ecordova/ecordova_directoryentry_private.h18
-rw-r--r--src/lib/ecordova/ecordova_directoryreader.c161
-rw-r--r--src/lib/ecordova/ecordova_directoryreader.eo32
-rw-r--r--src/lib/ecordova/ecordova_directoryreader_private.h18
-rw-r--r--src/lib/ecordova/ecordova_entry.c506
-rw-r--r--src/lib/ecordova/ecordova_entry.eo114
-rw-r--r--src/lib/ecordova/ecordova_entry_private.h53
-rw-r--r--src/lib/ecordova/ecordova_file.c128
-rw-r--r--src/lib/ecordova/ecordova_file.eo61
-rw-r--r--src/lib/ecordova/ecordova_file_private.h23
-rw-r--r--src/lib/ecordova/ecordova_fileentry.c109
-rw-r--r--src/lib/ecordova/ecordova_fileentry.eo48
-rw-r--r--src/lib/ecordova/ecordova_fileentry_private.h16
-rw-r--r--src/lib/ecordova/ecordova_filereader.c272
-rw-r--r--src/lib/ecordova/ecordova_filereader.eo92
-rw-r--r--src/lib/ecordova/ecordova_filereader_private.h26
-rw-r--r--src/lib/ecordova/ecordova_filesystem.c38
-rw-r--r--src/lib/ecordova/ecordova_filesystem.eo25
-rw-r--r--src/lib/ecordova/ecordova_filesystem_private.h16
-rw-r--r--src/lib/ecordova/ecordova_filetransfer.c613
-rw-r--r--src/lib/ecordova/ecordova_filetransfer.eo155
-rw-r--r--src/lib/ecordova/ecordova_filetransfer_private.h21
-rw-r--r--src/lib/ecordova/ecordova_filewriter.c357
-rw-r--r--src/lib/ecordova/ecordova_filewriter.eo112
-rw-r--r--src/lib/ecordova/ecordova_filewriter_private.h26
-rw-r--r--src/lib/ecordova/ecordova_geolocation.c282
-rw-r--r--src/lib/ecordova/ecordova_geolocation.eo152
-rw-r--r--src/lib/ecordova/ecordova_geolocation_private.h19
-rw-r--r--src/lib/ecordova/ecordova_globalization.c1122
-rw-r--r--src/lib/ecordova/ecordova_globalization.eo390
-rw-r--r--src/lib/ecordova/ecordova_globalization_private.h16
-rw-r--r--src/lib/ecordova/ecordova_inappbrowser.c78
-rw-r--r--src/lib/ecordova/ecordova_inappbrowser.eo89
-rw-r--r--src/lib/ecordova/ecordova_inappbrowser_private.h16
-rw-r--r--src/lib/ecordova/ecordova_main.c98
-rw-r--r--src/lib/ecordova/ecordova_media.c531
-rw-r--r--src/lib/ecordova/ecordova_media.eo108
-rw-r--r--src/lib/ecordova/ecordova_media_private.h26
-rw-r--r--src/lib/ecordova/ecordova_mediafile.c187
-rw-r--r--src/lib/ecordova/ecordova_mediafile.eo62
-rw-r--r--src/lib/ecordova/ecordova_mediafile_private.h21
-rw-r--r--src/lib/ecordova/ecordova_networkinformation.c98
-rw-r--r--src/lib/ecordova/ecordova_networkinformation.eo61
-rw-r--r--src/lib/ecordova/ecordova_networkinformation_private.h19
-rw-r--r--src/lib/ecordova/ecordova_private.h54
-rw-r--r--src/lib/ecordova/ecordova_splashscreen.c51
-rw-r--r--src/lib/ecordova/ecordova_splashscreen.eo29
-rw-r--r--src/lib/ecordova/ecordova_splashscreen_private.h16
-rw-r--r--src/lib/ecordova/ecordova_systeminfo.c139
-rw-r--r--src/lib/ecordova/ecordova_systeminfo.eo27
-rw-r--r--src/lib/ecordova/ecordova_systeminfo_private.h19
-rw-r--r--src/lib/ecordova/ecordova_vibration.c66
-rw-r--r--src/lib/ecordova/ecordova_vibration.eo30
-rw-r--r--src/lib/ecordova/ecordova_vibration_private.h16
-rw-r--r--src/tests/ecordova/44khz32kbps.mp3bin0 -> 220891 bytes
-rw-r--r--src/tests/ecordova/ecordova_batterystatus_test.c44
-rw-r--r--src/tests/ecordova/ecordova_batterystatus_test.h9
-rw-r--r--src/tests/ecordova/ecordova_console_test.c140
-rw-r--r--src/tests/ecordova/ecordova_console_test.h9
-rw-r--r--src/tests/ecordova/ecordova_contacts_test.c255
-rw-r--r--src/tests/ecordova/ecordova_contacts_test.h9
-rw-r--r--src/tests/ecordova/ecordova_device_test.c100
-rw-r--r--src/tests/ecordova/ecordova_device_test.h9
-rw-r--r--src/tests/ecordova/ecordova_devicemotion_test.c89
-rw-r--r--src/tests/ecordova/ecordova_devicemotion_test.h9
-rw-r--r--src/tests/ecordova/ecordova_deviceorientation_test.c89
-rw-r--r--src/tests/ecordova/ecordova_deviceorientation_test.h9
-rw-r--r--src/tests/ecordova/ecordova_directoryentry_test.c434
-rw-r--r--src/tests/ecordova/ecordova_directoryentry_test.h24
-rw-r--r--src/tests/ecordova/ecordova_directoryreader_test.c132
-rw-r--r--src/tests/ecordova/ecordova_directoryreader_test.h9
-rw-r--r--src/tests/ecordova/ecordova_entry_test.c748
-rw-r--r--src/tests/ecordova/ecordova_entry_test.h14
-rw-r--r--src/tests/ecordova/ecordova_file_test.c140
-rw-r--r--src/tests/ecordova/ecordova_file_test.h9
-rw-r--r--src/tests/ecordova/ecordova_fileentry_test.c211
-rw-r--r--src/tests/ecordova/ecordova_fileentry_test.h17
-rw-r--r--src/tests/ecordova/ecordova_filereader_test.c294
-rw-r--r--src/tests/ecordova/ecordova_filereader_test.h13
-rw-r--r--src/tests/ecordova/ecordova_filetransfer_test.c227
-rw-r--r--src/tests/ecordova/ecordova_filetransfer_test.h9
-rw-r--r--src/tests/ecordova/ecordova_filewriter_test.c218
-rw-r--r--src/tests/ecordova/ecordova_filewriter_test.h9
-rw-r--r--src/tests/ecordova/ecordova_geolocation_test.c93
-rw-r--r--src/tests/ecordova/ecordova_geolocation_test.h9
-rw-r--r--src/tests/ecordova/ecordova_globalization_test.c594
-rw-r--r--src/tests/ecordova/ecordova_globalization_test.h9
-rw-r--r--src/tests/ecordova/ecordova_media_test.c44
-rw-r--r--src/tests/ecordova/ecordova_media_test.h9
-rw-r--r--src/tests/ecordova/ecordova_mediafile_test.c142
-rw-r--r--src/tests/ecordova/ecordova_mediafile_test.h12
-rw-r--r--src/tests/ecordova/ecordova_networkinformation_test.c44
-rw-r--r--src/tests/ecordova/ecordova_networkinformation_test.h9
-rw-r--r--src/tests/ecordova/ecordova_suite.c163
-rw-r--r--src/tests/ecordova/ecordova_suite.h14
-rw-r--r--src/tests/ecordova/ecordova_vibration_test.c44
-rw-r--r--src/tests/ecordova/ecordova_vibration_test.h9
-rw-r--r--src/tests/evas/evas_test_textblock.c8
152 files changed, 17607 insertions, 1 deletions
diff --git a/cmakeconfig/EcordovaConfig.cmake.in b/cmakeconfig/EcordovaConfig.cmake.in
new file mode 100644
index 0000000000..9ca947c004
--- /dev/null
+++ b/cmakeconfig/EcordovaConfig.cmake.in
@@ -0,0 +1,32 @@
+# - Try to find ecordova
+# Once done this will define
+# ECORDOVA_FOUND - System has ecordova
+# ECORDOVA_INCLUDE_DIRS - The ecordova include directories
+# ECORDOVA_LIBRARIES - The libraries needed to use ecordova
+# ECORDOVA_DEFINITIONS - Compiler switches required for using ecordova
+
+set(MY_PKG ecordova)
+
+find_package(PkgConfig)
+if ("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER "2.8.1")
+ # "QUIET" was introduced in 2.8.2
+ set(_QUIET QUIET)
+endif ()
+pkg_check_modules(PC_LIBECORDOVA ${_QUIET} ${MY_PKG})
+
+find_library(ECORDOVA_LIBRARY
+ NAMES ${PC_LIBECORDOVA_LIBRARIES}
+ HINTS ${PC_LIBECORDOVA_LIBDIR} ${PC_LIBECORDOVA_LIBRARY_DIRS} )
+
+set(ECORDOVA_DEFINITIONS ${PC_LIBECORDOVA_CFLAGS_OTHER})
+set(ECORDOVA_LIBRARIES ${ECORDOVA_LIBRARY})
+set(ECORDOVA_INCLUDE_DIRS ${PC_LIBECORDOVA_INCLUDE_DIRS})
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set ECORDOVA_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(${MY_PKG} DEFAULT_MSG
+ ECORDOVA_LIBRARIES ECORDOVA_INCLUDE_DIRS)
+
+mark_as_advanced(ECORDOVA_INCLUDE_DIRS ECORDOVA_LIBRARY ECORDOVA_LIBRARIES ECORDOVA_DEFINITIONS)
+
diff --git a/cmakeconfig/EcordovaCxxConfig.cmake.in b/cmakeconfig/EcordovaCxxConfig.cmake.in
new file mode 100644
index 0000000000..ebd8414fb4
--- /dev/null
+++ b/cmakeconfig/EcordovaCxxConfig.cmake.in
@@ -0,0 +1,30 @@
+# - Try to find ecordova
+# Once done this will define
+# ECORDOVA_CXX_FOUND - System has ecordova
+# ECORDOVA_CXX_INCLUDE_DIRS - The ecordova include directories
+# ECORDOVA_CXX_LIBRARIES - The libraries needed to use ecordova
+# ECORDOVA_CXX_DEFINITIONS - Compiler switches required for using ecordova
+
+set(MY_PKG ecordova_cxx)
+
+find_package(PkgConfig)
+if ("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER "2.8.1")
+ # "QUIET" was introduced in 2.8.2
+ set(_QUIET QUIET)
+endif ()
+pkg_check_modules(PC_ECORDOVA_CXX ${_QUIET} ${MY_PKG})
+find_library(ECORDOVA_CXX_LIBRARY
+ NAMES ${PC_ECORDOVA_CXX_LIBRARIES}
+ HINTS ${PC_ECORDOVA_CXX_LIBDIR} ${PC_ECORDOVA_CXX_LIBRARY_DIRS} )
+
+set(ECORDOVA_CXX_DEFINITIONS ${PC_ECORDOVA_CXX_CFLAGS_OTHER})
+set(ECORDOVA_CXX_LIBRARIES ${ECORDOVA_CXX_LIBRARY})
+set(ECORDOVA_CXX_INCLUDE_DIRS ${PC_ECORDOVA_CXX_INCLUDE_DIRS})
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set ECORDOVA_CXX_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(${MY_PKG} DEFAULT_MSG
+ ECORDOVA_CXX_LIBRARIES ECORDOVA_CXX_INCLUDE_DIRS)
+
+mark_as_advanced(ECORDOVA_CXX_INCLUDE_DIRS ECORDOVA_CXX_LIBRARY ECORDOVA_CXX_LIBRARIES ECORDOVA_CXX_DEFINITIONS)
diff --git a/configure.ac b/configure.ac
index 929a088783..c6f0fbaabd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3911,7 +3911,7 @@ EFL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [emile])
ECORE_EVAS_MODULE([extn], [${want_ecore_evas_extn}])
ECORE_EVAS_MODULE([ews], [yes])
ECORE_EVAS_MODULE([fb], [${want_fb}])
-ECORE_EVAS_MODULE([drm], [${want_drm}],
+ECORE_EVAS_MODULE([drm], [${want_drm}],
[EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [${want_drm}], [ecore-drm])])
ECORE_EVAS_MODULE([gl-drm], [${want_gl_drm}],
[EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [${want_gl_drm}], [ecore-drm])])
@@ -4581,6 +4581,93 @@ EFL_ADD_LIBS([ELOCATION], [-lm])
EFL_LIB_END([Elocation])
#### End of Elocation
+
+
+#### Ecordova
+AC_ARG_WITH([ecordova],
+ [AS_HELP_STRING([--with-ecordova=tizen|none],[ecordova implementation: tizen or none. @<:@default=none@:>@])],
+ [build_ecordova=${withval}],
+ [build_ecordova="none"])
+
+want_ecordova_tizen="no"
+want_ecordova_none="no"
+want_ecordova="no"
+case "${build_ecordova}" in
+ tizen)
+ want_ecordova_tizen="yes"
+ want_ecordova="yes"
+ ;;
+ none)
+ want_ecordova_none="yes"
+ ;;
+ *)
+ AC_MSG_ERROR([Unknown build ecordova --with-ecordova=${build_ecordova}])
+ ;;
+esac
+
+AM_CONDITIONAL([HAVE_ECORDOVA], [test "x${want_ecordova}" = "xyes"])
+
+EFL_LIB_START_OPTIONAL([Ecordova], [test "x${want_ecordova}" = "xyes"])
+
+### Additional options to configure
+
+### Default values
+
+### Checks for programs
+
+### Checks for libraries
+
+EFL_INTERNAL_DEPEND_PKG([ECORDOVA], [eina])
+EFL_INTERNAL_DEPEND_PKG([ECORDOVA], [eo])
+EFL_INTERNAL_DEPEND_PKG([ECORDOVA], [efl])
+EFL_INTERNAL_DEPEND_PKG([ECORDOVA], [ecore])
+EFL_INTERNAL_DEPEND_PKG([ECORDOVA], [ecore-evas])
+EFL_INTERNAL_DEPEND_PKG([ECORDOVA], [ecore-file])
+
+EFL_OPTIONAL_DEPEND_PKG([ECORDOVA], [${want_ecordova_tizen}], [TIZEN_VCONF], [vconf])
+EFL_OPTIONAL_DEPEND_PKG([ECORDOVA], [${want_ecordova_tizen}], [TIZEN_CONTACTS_SERVICE], [contacts-service2])
+EFL_OPTIONAL_DEPEND_PKG([ECORDOVA], [${want_ecordova_tizen}], [TIZEN_INFO], [capi-system-info])
+EFL_OPTIONAL_DEPEND_PKG([ECORDOVA], [${want_ecordova_tizen}], [TIZEN_SENSOR], [capi-system-sensor])
+EFL_OPTIONAL_DEPEND_PKG([ECORDOVA], [${want_ecordova_tizen}], [TIZEN_LOCATION_MANAGER], [capi-location-manager])
+EFL_OPTIONAL_DEPEND_PKG([ECORDOVA], [${want_ecordova_tizen}], [TIZEN_HAPTIC], [capi-system-haptic])
+EFL_OPTIONAL_DEPEND_PKG([ECORDOVA], [${want_ecordova_tizen}], [TIZEN_NETWORK_CONNECTION], [capi-network-connection])
+EFL_OPTIONAL_DEPEND_PKG([ECORDOVA], [${want_ecordova_tizen}], [TIZEN_MEDIA_METADATA_EXTRACTOR], [capi-media-metadata-extractor])
+EFL_OPTIONAL_DEPEND_PKG([ECORDOVA], [${want_ecordova_tizen}], [TIZEN_MEDIA_PLAYER], [capi-media-player])
+EFL_OPTIONAL_DEPEND_PKG([ECORDOVA], [${want_ecordova_tizen}], [TIZEN_MEDIA_RECORDER], [capi-media-recorder])
+EFL_OPTIONAL_DEPEND_PKG([ECORDOVA], [${want_ecordova_tizen}], [TIZEN_BASE_UTILS_I18N], [capi-base-utils-i18n])
+
+EFL_ADD_LIBS([ECORDOVA], [-lm])
+
+EFL_EVAL_PKGS([ECORDOVA])
+
+### Checks for header files
+
+### Checks for types
+
+### Checks for structures
+
+### Checks for compiler characteristics
+
+### Checks for linker characteristics
+
+### Checks for library functions
+
+EFL_LIB_END_OPTIONAL([Ecordova])
+
+#### End of Ecordova
+
+
+#### Ecordova CXX
+EFL_LIB_START_OPTIONAL([Ecordova_Cxx], [test "x${want_ecordova}" = "xyes"])
+
+EFL_EVAL_PKGS([ECORDOVA_CXX])
+
+EFL_LIB_END_OPTIONAL([Ecordova_Cxx])
+#### End of Ecordova CXX
+
+
+
+
### Add Wayland server library if test is enabled
if test "x${want_tests}" = "xyes" -a "x${want_wayland}" = "xyes"; then
EFL_DEPEND_PKG([ECORE_WAYLAND_SRV], [WAYLAND], [wayland-server >= 1.8.0])
@@ -4769,6 +4856,8 @@ pc/ethumb.pc
pc/ethumb_client.pc
pc/elocation.pc
pc/elua.pc
+pc/ecordova.pc
+pc/ecordova-cxx.pc
dbus-services/org.enlightenment.Ethumb.service
systemd-services/ethumb.service
$po_makefile_in
@@ -4818,6 +4907,10 @@ cmakeconfig/EluaConfig.cmake
cmakeconfig/EluaConfigVersion.cmake:cmakeconfig/EFLConfigVersion.cmake.in
cmakeconfig/EmileConfig.cmake
cmakeconfig/EmileConfigVersion.cmake:cmakeconfig/EFLConfigVersion.cmake.in
+cmakeconfig/EcordovaConfig.cmake
+cmakeconfig/EcordovaConfigVersion.cmake:cmakeconfig/EFLConfigVersion.cmake.in
+cmakeconfig/EcordovaCxxConfig.cmake
+cmakeconfig/EcordovaCxxConfigVersion.cmake:cmakeconfig/EFLConfigVersion.cmake.in
])
AC_OUTPUT
@@ -4932,6 +5025,7 @@ echo "Emotion.........: yes (${features_emotion})"
echo "Ethumb..........: yes"
echo "Ethumb_Client...: yes"
echo "Elua............: $have_elua"
+echo "Ecordova........: ${efl_lib_optional_ecordova} (${COLOR_OTHER}${build_ecordova}${COLOR_RESET})"
if test "${build_tests}" = "none"; then
echo "Tests...........: no"
elif test "${build_tests}" = "auto"; then
diff --git a/pc/ecordova-cxx.pc.in b/pc/ecordova-cxx.pc.in
new file mode 100644
index 0000000000..8cfae25b2d
--- /dev/null
+++ b/pc/ecordova-cxx.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Ecordova C++
+Description: A C++ binding for the Ecordova library
+Requires.private: @requirements_pc_ecordova@ @requirements_pc_eo@
+Version: @VERSION@
+Libs: -L${libdir} -lecordova @requirements_public_libs_ecordova@ @requirements_public_libs_eo@
+Libs.private: @requirements_libs_ecordova@ @requirements_libs_eo@
+Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/eo-@VMAJ@ -I${includedir}/ecordova-@VMAJ@ -I${includedir}/ecordova-cxx-@VMAJ@
diff --git a/pc/ecordova.pc.in b/pc/ecordova.pc.in
new file mode 100644
index 0000000000..87c091c404
--- /dev/null
+++ b/pc/ecordova.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Ecordova
+Description: Cordova API eolification
+Requires.private: @requirements_pc_ecordova@
+Version: @VERSION@
+Libs: -L${libdir} -lecordova @requirements_public_libs_ecordova@
+Libs.private: @requirements_libs_ecordova@
+Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/ecordova-@VMAJ@
diff --git a/src/Makefile.am b/src/Makefile.am
index dccc538af2..28e8e83fbb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -74,6 +74,8 @@ include Makefile_Eio_Cxx.am
include Makefile_Elua.am
include Makefile_Elocation.am
+include Makefile_Ecordova.am
+include Makefile_Ecordova_Cxx.am
.PHONY: benchmark examples
diff --git a/src/Makefile_Ecordova.am b/src/Makefile_Ecordova.am
new file mode 100644
index 0000000000..1315925e53
--- /dev/null
+++ b/src/Makefile_Ecordova.am
@@ -0,0 +1,189 @@
+if HAVE_ECORDOVA
+### Library
+
+ecordova_eolian_files = \
+lib/ecordova/ecordova_systeminfo.eo \
+lib/ecordova/ecordova_batterystatus.eo \
+lib/ecordova/ecordova_console.eo \
+lib/ecordova/ecordova_contacts.eo \
+lib/ecordova/ecordova_contact.eo \
+lib/ecordova/ecordova_contactaddress.eo \
+lib/ecordova/ecordova_contactfield.eo \
+lib/ecordova/ecordova_contactname.eo \
+lib/ecordova/ecordova_contactorganization.eo \
+lib/ecordova/ecordova_device.eo \
+lib/ecordova/ecordova_devicemotion.eo \
+lib/ecordova/ecordova_deviceorientation.eo \
+lib/ecordova/ecordova_dialogs.eo \
+lib/ecordova/ecordova_geolocation.eo \
+lib/ecordova/ecordova_globalization.eo \
+lib/ecordova/ecordova_inappbrowser.eo \
+lib/ecordova/ecordova_media.eo \
+lib/ecordova/ecordova_networkinformation.eo \
+lib/ecordova/ecordova_splashscreen.eo \
+lib/ecordova/ecordova_vibration.eo \
+lib/ecordova/ecordova_file.eo \
+lib/ecordova/ecordova_filewriter.eo \
+lib/ecordova/ecordova_filereader.eo \
+lib/ecordova/ecordova_filesystem.eo \
+lib/ecordova/ecordova_entry.eo \
+lib/ecordova/ecordova_directoryentry.eo \
+lib/ecordova/ecordova_directoryreader.eo \
+lib/ecordova/ecordova_fileentry.eo \
+lib/ecordova/ecordova_mediafile.eo \
+lib/ecordova/ecordova_filetransfer.eo \
+lib/ecordova/ecordova_capture.eo
+
+ecordova_eolian_c = $(ecordova_eolian_files:%.eo=%.eo.c)
+ecordova_eolian_h = $(ecordova_eolian_files:%.eo=%.eo.h)
+
+BUILT_SOURCES += \
+ $(ecordova_eolian_c) \
+ $(ecordova_eolian_h)
+
+CLEANFILES += \
+ $(ecordova_eolian_c) \
+ $(ecordova_eolian_h)
+
+ecordovaeolianfilesdir = $(datadir)/eolian/include/ecordova-@VMAJ@
+ecordovaeolianfiles_DATA = \
+ $(ecordova_eolian_files)
+
+EXTRA_DIST += \
+ ${ecordovaeolianfiles_DATA}
+
+lib_LTLIBRARIES += lib/ecordova/libecordova.la
+
+installed_ecordovamainheadersdir = $(includedir)/ecordova-@VMAJ@
+dist_installed_ecordovamainheaders_DATA = \
+lib/ecordova/Ecordova.h \
+lib/ecordova/Ecordova_Common.h \
+lib/ecordova/Ecordova_Eo.h
+
+nodist_installed_ecordovamainheaders_DATA = \
+ $(ecordova_eolian_h)
+
+lib_ecordova_libecordova_la_SOURCES = \
+lib/ecordova/ecordova_main.c \
+lib/ecordova/ecordova_private.h \
+lib/ecordova/ecordova_systeminfo.c \
+lib/ecordova/ecordova_batterystatus.c \
+lib/ecordova/ecordova_console.c \
+lib/ecordova/ecordova_contacts.c \
+lib/ecordova/ecordova_contact.c \
+lib/ecordova/ecordova_contactaddress.c \
+lib/ecordova/ecordova_contactfield.c \
+lib/ecordova/ecordova_contactname.c \
+lib/ecordova/ecordova_contactorganization.c \
+lib/ecordova/ecordova_contacts_record_utils.c \
+lib/ecordova/ecordova_device.c \
+lib/ecordova/ecordova_devicemotion.c \
+lib/ecordova/ecordova_deviceorientation.c \
+lib/ecordova/ecordova_dialogs.c \
+lib/ecordova/ecordova_geolocation.c \
+lib/ecordova/ecordova_globalization.c \
+lib/ecordova/ecordova_inappbrowser.c \
+lib/ecordova/ecordova_media.c \
+lib/ecordova/ecordova_networkinformation.c \
+lib/ecordova/ecordova_splashscreen.c \
+lib/ecordova/ecordova_vibration.c \
+lib/ecordova/ecordova_file.c \
+lib/ecordova/ecordova_filewriter.c \
+lib/ecordova/ecordova_filereader.c \
+lib/ecordova/ecordova_filesystem.c \
+lib/ecordova/ecordova_entry.c \
+lib/ecordova/ecordova_directoryentry.c \
+lib/ecordova/ecordova_directoryreader.c \
+lib/ecordova/ecordova_fileentry.c \
+lib/ecordova/ecordova_mediafile.c \
+lib/ecordova/ecordova_filetransfer.c \
+lib/ecordova/ecordova_capture.c
+
+lib_ecordova_libecordova_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ECORDOVA_CFLAGS@ @EFL_CFLAGS@
+lib_ecordova_libecordova_la_LIBADD = @ECORDOVA_LIBS@ @EFL_LIBS@
+lib_ecordova_libecordova_la_DEPENDENCIES = @ECORDOVA_INTERNAL_LIBS@ @EFL_INTERNAL_LIBS@
+lib_ecordova_libecordova_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@
+
+### Unit tests
+
+if EFL_ENABLE_TESTS
+
+check_PROGRAMS += tests/ecordova/ecordova_suite
+TESTS += tests/ecordova/ecordova_suite
+
+tests_ecordova_ecordova_suite_SOURCES = \
+tests/ecordova/ecordova_suite.c \
+tests/ecordova/ecordova_suite.h \
+tests/ecordova/ecordova_contacts_test.c \
+tests/ecordova/ecordova_contacts_test.h \
+tests/ecordova/ecordova_device_test.c \
+tests/ecordova/ecordova_device_test.h \
+tests/ecordova/ecordova_devicemotion_test.c \
+tests/ecordova/ecordova_devicemotion_test.h \
+tests/ecordova/ecordova_deviceorientation_test.c \
+tests/ecordova/ecordova_deviceorientation_test.h \
+tests/ecordova/ecordova_geolocation_test.c \
+tests/ecordova/ecordova_geolocation_test.h \
+tests/ecordova/ecordova_batterystatus_test.c \
+tests/ecordova/ecordova_batterystatus_test.h \
+tests/ecordova/ecordova_console_test.c \
+tests/ecordova/ecordova_console_test.h \
+tests/ecordova/ecordova_filetransfer_test.c \
+tests/ecordova/ecordova_filetransfer_test.h \
+tests/ecordova/ecordova_media_test.c \
+tests/ecordova/ecordova_media_test.h \
+tests/ecordova/ecordova_networkinformation_test.c \
+tests/ecordova/ecordova_networkinformation_test.h \
+tests/ecordova/ecordova_vibration_test.c \
+tests/ecordova/ecordova_vibration_test.h \
+tests/ecordova/ecordova_directoryreader_test.c \
+tests/ecordova/ecordova_directoryreader_test.h \
+tests/ecordova/ecordova_directoryentry_test.c \
+tests/ecordova/ecordova_directoryentry_test.h \
+tests/ecordova/ecordova_entry_test.c \
+tests/ecordova/ecordova_entry_test.h \
+tests/ecordova/ecordova_file_test.c \
+tests/ecordova/ecordova_file_test.h \
+tests/ecordova/ecordova_fileentry_test.c \
+tests/ecordova/ecordova_fileentry_test.h \
+tests/ecordova/ecordova_filereader_test.c \
+tests/ecordova/ecordova_filereader_test.h \
+tests/ecordova/ecordova_filewriter_test.c \
+tests/ecordova/ecordova_filewriter_test.h \
+tests/ecordova/ecordova_mediafile_test.c \
+tests/ecordova/ecordova_mediafile_test.h \
+tests/ecordova/ecordova_globalization_test.c \
+tests/ecordova/ecordova_globalization_test.h
+
+tests_ecordova_ecordova_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
+-DTESTS_SRC_DIR=\"$(abs_top_srcdir)/src/tests/ecordova\" \
+-DTESTS_BUILD_DIR=\"$(abs_top_builddir)/src/tests/ecordova\" \
+@CHECK_CFLAGS@ \
+@ECORDOVA_CFLAGS@ @EFL_CFLAGS@
+
+tests_ecordova_ecordova_suite_LDADD = \
+@CHECK_LIBS@ \
+@USE_ECORDOVA_LIBS@ \
+@USE_EFL_LIBS@
+
+tests_ecordova_ecordova_suite_DEPENDENCIES = \
+@USE_ECORDOVA_INTERNAL_LIBS@
+
+endif
+
+EXTRA_DIST += $(ECORDOVA_DATA_FILES)
+
+if HAVE_ELUA
+
+ecordova_eolian_lua = $(ecordova_eolian_files:%.eo=%.eo.lua)
+
+generated_ecordova_lua_all = $(ecordova_eolian_lua)
+
+CLEANFILES += $(generated_ecordova_lua_all)
+
+installed_ecordovaluadir = $(datadir)/elua/modules/ecordova
+nodist_installed_ecordovalua_DATA = $(generated_ecordova_lua_all)
+
+endif
+
+endif
diff --git a/src/Makefile_Ecordova_Cxx.am b/src/Makefile_Ecordova_Cxx.am
new file mode 100644
index 0000000000..764a55f5fa
--- /dev/null
+++ b/src/Makefile_Ecordova_Cxx.am
@@ -0,0 +1,22 @@
+if HAVE_CXX11
+
+### Generated headers
+
+generated_ecordova_cxx_bindings = $(ecordova_eolian_files:%.eo=%.eo.hh)
+
+lib/ecordova/Ecordova.hh: $(generated_ecordova_cxx_bindings)
+ @echo @ECHO_E@ "#ifndef EFL_CXX_ECORDOVA_HH\n#define EFL_CXX_ECORDOVA_HH\n" > $(top_builddir)/src/lib/ecordova/Ecordova.hh
+ @echo @ECHO_E@ "#ifdef EFL_BETA_API_SUPPORT" >> $(top_builddir)/src/lib/ecordova/Ecordova.hh
+ @for i in $(generated_ecordova_cxx_bindings); do echo "#include <$$(basename $$i)>" >> $(top_builddir)/src/lib/ecordova/Ecordova.hh; done
+ @echo @ECHO_E@ "#endif\n\n#endif\n" >> $(top_builddir)/src/lib/ecordova/Ecordova.hh
+
+generated_ecordova_cxx_all = \
+ $(generated_ecordova_cxx_bindings) \
+ lib/ecordova/Ecordova.hh
+
+CLEANFILES += $(generated_ecordova_cxx_all)
+
+installed_ecordovacxxmainheadersdir = $(includedir)/ecordova-cxx-@VMAJ@/
+nodist_installed_ecordovacxxmainheaders_DATA = $(generated_ecordova_cxx_all)
+
+endif
diff --git a/src/lib/ecordova/Ecordova.h b/src/lib/ecordova/Ecordova.h
new file mode 100644
index 0000000000..46396e02af
--- /dev/null
+++ b/src/lib/ecordova/Ecordova.h
@@ -0,0 +1,50 @@
+#ifndef _ECORDOVA_H
+#define _ECORDOVA_H
+
+#include <Ecore.h>
+#include <Efl.h>
+#include <Efl_Config.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORDOVA_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_ECORDOVA_BUILD */
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "Ecordova_Common.h"
+#ifdef EFL_EO_API_SUPPORT
+#include "Ecordova_Eo.h"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#undef EAPI
+#define EAPI
+
+#endif
diff --git a/src/lib/ecordova/Ecordova_Common.h b/src/lib/ecordova/Ecordova_Common.h
new file mode 100644
index 0000000000..b1e45cf1a9
--- /dev/null
+++ b/src/lib/ecordova/Ecordova_Common.h
@@ -0,0 +1,13 @@
+/**
+ * @brief Initialize ecordova.
+ *
+ * @return 1 or greater on success, 0 otherwise
+ */
+EAPI int ecordova_init(void);
+
+/**
+ * @brief Shutdown ecordova.
+ *
+ * @return 0 if ecordova shuts down, greater than 0 otherwise.
+ */
+EAPI int ecordova_shutdown(void);
diff --git a/src/lib/ecordova/Ecordova_Eo.h b/src/lib/ecordova/Ecordova_Eo.h
new file mode 100644
index 0000000000..d1da074fd3
--- /dev/null
+++ b/src/lib/ecordova/Ecordova_Eo.h
@@ -0,0 +1,34 @@
+#include <Efl.h>
+
+typedef Eo Ecordova_DirectoryReader;
+
+#include <ecordova_batterystatus.eo.h>
+#include <ecordova_console.eo.h>
+#include <ecordova_contactaddress.eo.h>
+#include <ecordova_contactfield.eo.h>
+#include <ecordova_contactname.eo.h>
+#include <ecordova_contactorganization.eo.h>
+#include <ecordova_contact.eo.h>
+#include <ecordova_contacts.eo.h>
+#include <ecordova_device.eo.h>
+#include <ecordova_devicemotion.eo.h>
+#include <ecordova_deviceorientation.eo.h>
+#include <ecordova_dialogs.eo.h>
+#include <ecordova_geolocation.eo.h>
+#include <ecordova_globalization.eo.h>
+#include <ecordova_inappbrowser.eo.h>
+#include <ecordova_media.eo.h>
+#include <ecordova_networkinformation.eo.h>
+#include <ecordova_splashscreen.eo.h>
+#include <ecordova_vibration.eo.h>
+#include <ecordova_file.eo.h>
+#include <ecordova_filewriter.eo.h>
+#include <ecordova_filereader.eo.h>
+#include <ecordova_filesystem.eo.h>
+#include <ecordova_entry.eo.h>
+#include <ecordova_directoryentry.eo.h>
+#include <ecordova_directoryreader.eo.h>
+#include <ecordova_fileentry.eo.h>
+#include <ecordova_mediafile.eo.h>
+#include <ecordova_filetransfer.eo.h>
+#include <ecordova_capture.eo.h>
diff --git a/src/lib/ecordova/ecordova_batterystatus.c b/src/lib/ecordova/ecordova_batterystatus.c
new file mode 100644
index 0000000000..a864e733df
--- /dev/null
+++ b/src/lib/ecordova/ecordova_batterystatus.c
@@ -0,0 +1,196 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_batterystatus_private.h"
+#include "ecordova_systeminfo.eo.h"
+
+#include <vconf.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define MY_CLASS ECORDOVA_BATTERYSTATUS_CLASS
+#define MY_CLASS_NAME "Ecordova_BatteryStatus"
+
+#define STATUS_CRITICAL 5
+#define STATUS_LOW 20
+
+static Eina_Bool _add_cb(void *, Eo *, const Eo_Event_Description *, void *);
+static Eina_Bool _del_cb(void *, Eo *, const Eo_Event_Description *, void *);
+static void _start(Ecordova_BatteryStatus_Data *);
+static void _stop(Ecordova_BatteryStatus_Data *);
+static Eina_Bool _on_battery_changed(void *, Eo *, const Eo_Event_Description *, void *);
+static bool _fetch_level(int *);
+static bool _fetch_charging_is(Eina_Bool *);
+
+static Eo_Base *
+_ecordova_batterystatus_eo_base_constructor(Eo *obj,
+ Ecordova_BatteryStatus_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_batterystatus_constructor(Eo *obj,
+ Ecordova_BatteryStatus_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ eo_do(obj, eo_event_callback_add(EO_EV_CALLBACK_ADD, _add_cb, pd));
+ eo_do(obj, eo_event_callback_add(EO_EV_CALLBACK_DEL, _del_cb, pd));
+}
+
+static void
+_ecordova_batterystatus_eo_base_destructor(Eo *obj,
+ Ecordova_BatteryStatus_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ if (pd->callback_ref_count)
+ _stop(pd);
+
+ eo_do(obj, eo_event_callback_del(EO_EV_CALLBACK_ADD, _add_cb, pd));
+ eo_do(obj, eo_event_callback_del(EO_EV_CALLBACK_DEL, _del_cb, pd));
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static Eina_Bool
+_add_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc,
+ void *event_info)
+{
+ Ecordova_BatteryStatus_Data *pd = (Ecordova_BatteryStatus_Data*)data;
+ const Eo_Callback_Array_Item *array = (const Eo_Callback_Array_Item*)event_info;
+
+ for (size_t i = 0; (desc = array[i].desc); ++i)
+ {
+ if (ECORDOVA_BATTERYSTATUS_EVENT_BATTERY_STATUS == desc ||
+ ECORDOVA_BATTERYSTATUS_EVENT_BATTERY_CRITICAL == desc ||
+ ECORDOVA_BATTERYSTATUS_EVENT_BATTERY_LOW == desc)
+ {
+ ++pd->callback_ref_count;
+ if (1 == pd->callback_ref_count)
+ _start(pd);
+ }
+ }
+
+ return EO_CALLBACK_CONTINUE;
+}
+
+static Eina_Bool
+_del_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc,
+ void *event_info)
+{
+ Ecordova_BatteryStatus_Data *pd = (Ecordova_BatteryStatus_Data*)data;
+ const Eo_Callback_Array_Item *array = (const Eo_Callback_Array_Item*)event_info;
+
+ for (size_t i = 0; (desc = array[i].desc); ++i)
+ {
+ if (ECORDOVA_BATTERYSTATUS_EVENT_BATTERY_STATUS == desc ||
+ ECORDOVA_BATTERYSTATUS_EVENT_BATTERY_CRITICAL == desc ||
+ ECORDOVA_BATTERYSTATUS_EVENT_BATTERY_LOW == desc)
+ --pd->callback_ref_count;
+ }
+
+ if (0 == pd->callback_ref_count)
+ _stop(pd);
+
+ return EO_CALLBACK_CONTINUE;
+}
+
+static void
+_start(Ecordova_BatteryStatus_Data *pd)
+{
+ eo_do(_ecordova_systeminfo,
+ eo_event_callback_add(ECORDOVA_SYSTEMINFO_EVENT_BATTERY_CHANGED,
+ _on_battery_changed,
+ pd));
+}
+
+static void
+_stop(Ecordova_BatteryStatus_Data *pd)
+{
+ free(pd->info);
+ pd->info = NULL;
+
+ eo_do(_ecordova_systeminfo,
+ eo_event_callback_del(ECORDOVA_SYSTEMINFO_EVENT_BATTERY_CHANGED,
+ _on_battery_changed,
+ pd));
+}
+
+static bool
+_fetch_level(int *level)
+{
+ int value = 0;
+ bool ret = vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, &value) == 0;
+ if (ret)
+ ERR("%s", "Failed to get battery capacity");
+
+ *level = value;
+ return ret;
+}
+
+static bool
+_fetch_charging_is(Eina_Bool *charging_is)
+{
+ int value = 0;
+ int ret = vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, &value) == 0;
+ if (!ret)
+ ERR("%s", "Failed to get battery change");
+
+ *charging_is = (0 != value) ? EINA_TRUE : EINA_FALSE;
+ return ret;
+}
+
+static Eina_Bool
+_on_battery_changed(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ Ecordova_BatteryStatus_Data *pd = (Ecordova_BatteryStatus_Data*)data;
+
+ Ecordova_BatteryStatus_EventInfo info;
+ if (!_fetch_level(&info.level) ||
+ !_fetch_charging_is(&info.plugged_is))
+ return EO_CALLBACK_CONTINUE;
+
+ if (!pd->info ||
+ pd->info->level != info.level ||
+ pd->info->plugged_is != info.plugged_is)
+ {
+ eo_do(pd->obj, eo_event_callback_call
+ (ECORDOVA_BATTERYSTATUS_EVENT_BATTERY_STATUS, &info));
+
+ if (!info.plugged_is)
+ {
+ if ((!pd->info || pd->info->level > STATUS_CRITICAL) &&
+ info.level <= STATUS_CRITICAL)
+ eo_do(pd->obj, eo_event_callback_call
+ (ECORDOVA_BATTERYSTATUS_EVENT_BATTERY_CRITICAL, &info));
+ else
+ if ((!pd->info || pd->info->level > STATUS_LOW) &&
+ info.level <= STATUS_LOW)
+ eo_do(pd->obj, eo_event_callback_call
+ (ECORDOVA_BATTERYSTATUS_EVENT_BATTERY_LOW, &info));
+ }
+
+ if (!pd->info)
+ pd->info = malloc(sizeof(Ecordova_BatteryStatus_EventInfo));
+ *pd->info = info;
+ }
+ return EO_CALLBACK_CONTINUE;
+}
+
+#include "ecordova_batterystatus.eo.c"
diff --git a/src/lib/ecordova/ecordova_batterystatus.eo b/src/lib/ecordova/ecordova_batterystatus.eo
new file mode 100644
index 0000000000..2dcb511c73
--- /dev/null
+++ b/src/lib/ecordova/ecordova_batterystatus.eo
@@ -0,0 +1,51 @@
+struct Ecordova.BatteryStatus.EventInfo {
+ [[The battery status event info is passed an object that contains two
+ properties.
+ ]]
+
+ level: int;
+ [[The percentage of battery charge (0-100).]]
+
+ plugged_is: bool;
+ [[A boolean that indicates whether the device is plugged in.]]
+}
+
+class Ecordova.BatteryStatus (Eo.Base) {
+ [[Ecordova Battery Plugin
+ Plugin ID: org.apache.cordova.battery-status
+ http://plugins.cordova.io/#/package/org.apache.cordova.battery-status
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_BatteryStatus constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ battery,status: const(Ecordova.BatteryStatus.EventInfo)*;
+ [[This event fires when the percentage of battery charge changes by at
+ least 1 percent, or if the device is plugged in or unplugged.
+ ]]
+
+ battery,critical: const(Ecordova.BatteryStatus.EventInfo)*;
+ [[This event fires when the percentage of battery charge has reached
+ the critical battery threshold. The value is device-specific.
+ ]]
+
+ battery,low: const(Ecordova.BatteryStatus.EventInfo)*;
+ [[This event fires when the percentage of battery charge has reached
+ the low battery threshold, device-specific value.
+ ]]
+ }
+}
diff --git a/src/lib/ecordova/ecordova_batterystatus_private.h b/src/lib/ecordova/ecordova_batterystatus_private.h
new file mode 100644
index 0000000000..f9ced32f04
--- /dev/null
+++ b/src/lib/ecordova/ecordova_batterystatus_private.h
@@ -0,0 +1,19 @@
+#ifndef _ECORDOVA_BATTERYSTATUS_PRIVATE_H
+#define _ECORDOVA_BATTERYSTATUS_PRIVATE_H
+
+#include "ecordova_private.h"
+#include "ecordova_batterystatus.eo.h"
+
+typedef struct _Ecordova_BatteryStatus_Data Ecordova_BatteryStatus_Data;
+
+/**
+ * Ecordova.BatteryStatus private data
+ */
+struct _Ecordova_BatteryStatus_Data
+{
+ Eo *obj;
+ int callback_ref_count;
+ Ecordova_BatteryStatus_EventInfo *info;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_capture.c b/src/lib/ecordova/ecordova_capture.c
new file mode 100644
index 0000000000..c17b1dad12
--- /dev/null
+++ b/src/lib/ecordova/ecordova_capture.c
@@ -0,0 +1,60 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_capture_private.h"
+
+#define MY_CLASS ECORDOVA_CAPTURE_CLASS
+#define MY_CLASS_NAME "Ecordova_Capture"
+
+static Eo_Base *
+_ecordova_capture_eo_base_constructor(Eo *obj, Ecordova_Capture_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_capture_constructor(Eo *obj EINA_UNUSED,
+ Ecordova_Capture_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+}
+
+static void
+_ecordova_capture_eo_base_destructor(Eo *obj,
+ Ecordova_Capture_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_capture_audio_capture(Eo *obj EINA_UNUSED,
+ Ecordova_Capture_Data *pd EINA_UNUSED,
+ const Ecordova_Capture_AudioOptions *options EINA_UNUSED)
+{
+ ERR("Not implemented.");
+}
+
+static void
+_ecordova_capture_image_capture(Eo *obj EINA_UNUSED,
+ Ecordova_Capture_Data *pd EINA_UNUSED,
+ const Ecordova_Capture_ImageOptions *options EINA_UNUSED)
+{
+ ERR("Not implemented.");
+}
+
+static void
+_ecordova_capture_video_capture(Eo *obj EINA_UNUSED,
+ Ecordova_Capture_Data *pd EINA_UNUSED,
+ const Ecordova_Capture_VideoOptions *options EINA_UNUSED)
+{
+ ERR("Not implemented.");
+}
+
+#include "ecordova_capture.eo.c"
diff --git a/src/lib/ecordova/ecordova_capture.eo b/src/lib/ecordova/ecordova_capture.eo
new file mode 100644
index 0000000000..cef42940f0
--- /dev/null
+++ b/src/lib/ecordova/ecordova_capture.eo
@@ -0,0 +1,178 @@
+enum Ecordova.Capture.ErrorCode {
+ CAPTURE_INTERNAL_ERR,
+ [[The camera or microphone failed to capture image or sound.]]
+
+ CAPTURE_APPLICATION_BUSY,
+ [[The camera or audio capture application is currently serving another capture request.]]
+
+ CAPTURE_INVALID_ARGUMENT,
+ [[Invalid use of the API (e.g., the value of limit is less than one).]]
+
+ CAPTURE_NO_MEDIA_FILES,
+ [[The user exits the camera or audio capture application before capturing anything.]]
+
+ CAPTURE_NOT_SUPPORTED
+ [[The requested capture operation is not supported.]]
+
+}
+
+struct Ecordova.Capture.Error {
+ code: Ecordova.Capture.ErrorCode; [[One of the pre-defined error codes]]
+}
+
+struct Ecordova.Capture.AudioOptions {
+ [[Encapsulates audio capture configuration options.]]
+
+ limit: int;
+ [[The maximum number of audio clips the device user can record in a single
+ capture operation. The value must be greater than or equal to 1 (defaults to 1).]]
+
+ duration: int;
+ [[The maximum duration of an audio sound clip, in seconds.]]
+}
+
+struct Ecordova.Capture.ImageOptions {
+ [[Encapsulates image capture configuration options.]]
+
+ limit: int;
+ [[The maximum number of images the user can capture in a single capture
+ operation. The value must be greater than or equal to 1 (defaults to 1).]]
+}
+
+struct Ecordova.Capture.VideoOptions {
+ [[Encapsulates video capture configuration options.]]
+
+ limit: int;
+ [[The maximum number of video clips the device's user can capture in a
+ single capture operation. The value must be greater than or equal to 1 (defaults to 1).]]
+
+ duration: int;
+ [[The maximum duration of a video clip, in seconds.]]
+}
+
+class Ecordova.Capture (Eo.Base) {
+ [[Ecordova Media-Capture Plugin
+ Plugin ID: org.apache.cordova.media-capture
+ http://plugins.cordova.io/#/package/org.apache.cordova.media-capture
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_Capture constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ }
+ audio_capture {
+ [[Start the audio recorder application and return information
+ about captured audio clip files.
+
+ Starts an asynchronous operation to capture audio recordings
+ using the device's default audio recording application. The
+ operation allows the device user to capture multiple recordings
+ in a single session.
+
+ The capture operation ends when either the user exits the audio
+ recording application, or the maximum number of recordings
+ specified by CaptureAudioOptions.limit is reached. If no limit
+ parameter value is specified, it defaults to one (1), and the
+ capture operation terminates after the user records a single
+ audio clip.
+
+ When the capture operation finishes, the CaptureCallback
+ executes with an array of MediaFile objects describing each
+ captured audio clip file. If the user terminates the operation
+ before an audio clip is captured, the CaptureErrorCallback
+ executes with a CaptureError object, featuring the
+ CaptureError.CAPTURE_NO_MEDIA_FILES error code.
+ ]]
+ params {
+ options: const(Ecordova.Capture.AudioOptions)*;
+ }
+ }
+ image_capture {
+ [[Start the camera application and return information about
+ captured image files.
+
+ Starts an asynchronous operation to capture images using the
+ device's camera application. The operation allows users to
+ capture more than one image in a single session.
+
+ The capture operation ends either when the user closes the
+ camera application, or the maximum number of recordings
+ specified by CaptureAudioOptions.limit is reached. If no limit
+ value is specified, it defaults to one (1), and the capture
+ operation terminates after the user captures a single image.
+
+ When the capture operation finishes, it invokes the CaptureCB
+ callback with an array of MediaFile objects describing each
+ captured image file. If the user terminates the operation before
+ capturing an image, the CaptureErrorCB callback executes with a
+ CaptureError object featuring a
+ CaptureError.CAPTURE_NO_MEDIA_FILES error code.
+ ]]
+ params {
+ options: const(Ecordova.Capture.ImageOptions)*;
+ }
+ }
+ video_capture {
+ [[Start the video recorder application and return information
+ about captured video clip files.
+
+ Starts an asynchronous operation to capture video recordings
+ using the device's video recording application. The operation
+ allows the user to capture more than one recordings in a single
+ session.
+
+ The capture operation ends when either the user exits the video
+ recording application, or the maximum number of recordings
+ specified by CaptureVideoOptions.limit is reached. If no limit
+ parameter value is specified, it defaults to one (1), and the
+ capture operation terminates after the user records a single
+ video clip.
+
+ When the capture operation finishes, it the CaptureCB callback
+ executes with an array of MediaFile objects describing each
+ captured video clip file. If the user terminates the operation
+ before capturing a video clip, the CaptureErrorCB callback
+ executes with a CaptureError object featuring a
+ CaptureError.CAPTURE_NO_MEDIA_FILES error code.
+ ]]
+ params {
+ options: const(Ecordova.Capture.VideoOptions)*;
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ success: const(array<MediaFile*>)*;
+ [[Invoked upon a successful media capture operation.
+
+ This function executes after a successful capture operation
+ completes. At this point a media file has been captured, and either
+ the user has exited the media capture application, or the capture
+ limit has been reached.
+
+ Each MediaFile object describes a captured media file.
+ ]]
+
+ error: const(Ecordova.Capture.Error)*;
+ [[Invoked if an error occurs during a media capture operation.
+
+ This function executes if an error occurs when trying to launch a
+ media capture operation. Failure scenarios include when the capture
+ application is busy, a capture operation is already taking place, or
+ the user cancels the operation before any media files are captured.
+
+ This function executes with a CaptureError object containing an
+ appropriate error code.
+ ]]
+ }
+}
diff --git a/src/lib/ecordova/ecordova_capture_private.h b/src/lib/ecordova/ecordova_capture_private.h
new file mode 100644
index 0000000000..bea0c4207a
--- /dev/null
+++ b/src/lib/ecordova/ecordova_capture_private.h
@@ -0,0 +1,16 @@
+#ifndef _ECORDOVA_CAPTURE_PRIVATE_H
+#define _ECORDOVA_CAPTURE_PRIVATE_H
+
+#include "ecordova_private.h"
+
+typedef struct _Ecordova_Capture_Data Ecordova_Capture_Data;
+
+/**
+ * Ecordova.Capture private data
+ */
+struct _Ecordova_Capture_Data
+{
+ Eo *obj;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_console.c b/src/lib/ecordova/ecordova_console.c
new file mode 100644
index 0000000000..fd3c5ff408
--- /dev/null
+++ b/src/lib/ecordova/ecordova_console.c
@@ -0,0 +1,175 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_console_private.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define MY_CLASS ECORDOVA_CONSOLE_CLASS
+#define MY_CLASS_NAME "Ecordova_Console"
+
+static void _ecordova_console_level_log(Ecordova_Console_Data *, Ecordova_Console_LoggerLevel, const char *);
+
+static Eo_Base *
+_ecordova_console_eo_base_constructor(Eo *obj, Ecordova_Console_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->logger_use = EINA_TRUE;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_console_constructor(Eo *obj EINA_UNUSED,
+ Ecordova_Console_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+}
+
+static void
+_ecordova_console_eo_base_destructor(Eo *obj,
+ Ecordova_Console_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static Ecordova_Console_LoggerLevel
+_ecordova_console_level_get(Eo *obj EINA_UNUSED, Ecordova_Console_Data *pd)
+{
+ return pd->level;
+}
+
+static void
+_ecordova_console_level_set(Eo *obj EINA_UNUSED,
+ Ecordova_Console_Data *pd,
+ Ecordova_Console_LoggerLevel value)
+{
+ pd->level = value;
+}
+
+static Eina_Bool
+_ecordova_console_console_use_get(Eo *obj EINA_UNUSED, Ecordova_Console_Data *pd)
+{
+ return pd->console_use;
+}
+
+static void
+_ecordova_console_console_use_set(Eo *obj EINA_UNUSED,
+ Ecordova_Console_Data *pd,
+ Eina_Bool value)
+{
+ pd->console_use = value;
+}
+
+static Eina_Bool
+_ecordova_console_logger_use_get(Eo *obj EINA_UNUSED, Ecordova_Console_Data *pd)
+{
+ return pd->logger_use;
+}
+
+static void
+_ecordova_console_logger_use_set(Eo *obj EINA_UNUSED,
+ Ecordova_Console_Data *pd,
+ Eina_Bool value)
+{
+ pd->logger_use = value;
+}
+
+static void
+_ecordova_console_log(Eo *obj EINA_UNUSED,
+ Ecordova_Console_Data *pd,
+ const char *message)
+{
+ _ecordova_console_level_log(pd, ECORDOVA_CONSOLE_LOGGERLEVEL_LOG, message);
+}
+
+static void
+_ecordova_console_error(Eo *obj EINA_UNUSED,
+ Ecordova_Console_Data *pd,
+ const char *message)
+{
+ _ecordova_console_level_log(pd, ECORDOVA_CONSOLE_LOGGERLEVEL_ERROR, message);
+}
+
+static void
+_ecordova_console_warn(Eo *obj EINA_UNUSED,
+ Ecordova_Console_Data *pd,
+ const char *message)
+{
+ _ecordova_console_level_log(pd, ECORDOVA_CONSOLE_LOGGERLEVEL_WARN, message);
+}
+
+static void
+_ecordova_console_info(Eo *obj EINA_UNUSED,
+ Ecordova_Console_Data *pd,
+ const char *message)
+{
+ _ecordova_console_level_log(pd, ECORDOVA_CONSOLE_LOGGERLEVEL_INFO, message);
+}
+
+static void
+_ecordova_console_debug(Eo *obj EINA_UNUSED,
+ Ecordova_Console_Data *pd,
+ const char *message)
+{
+ _ecordova_console_level_log(pd, ECORDOVA_CONSOLE_LOGGERLEVEL_DEBUG, message);
+}
+
+static void
+_ecordova_console_level_log(Ecordova_Console_Data *pd,
+ Ecordova_Console_LoggerLevel level,
+ const char *message)
+{
+ EINA_SAFETY_ON_NULL_RETURN(message);
+
+ if (level < 0 || pd->level >= ECORDOVA_CONSOLE_LOGGERLEVEL_LAST)
+ {
+ ERR("Invalid logging level: %d", level);
+ return;
+ }
+
+ if (level > pd->level) return;
+
+ if (pd->logger_use)
+ {
+ switch (level)
+ {
+ case ECORDOVA_CONSOLE_LOGGERLEVEL_LOG:
+ CRI("%s", message);
+ break;
+ case ECORDOVA_CONSOLE_LOGGERLEVEL_ERROR:
+ ERR("%s", message);
+ break;
+ case ECORDOVA_CONSOLE_LOGGERLEVEL_WARN:
+ WRN("%s", message);
+ break;
+ case ECORDOVA_CONSOLE_LOGGERLEVEL_INFO:
+ INF("%s", message);
+ break;
+ case ECORDOVA_CONSOLE_LOGGERLEVEL_DEBUG:
+ DBG("%s", message);
+ break;
+ default: break; // removes warning
+ }
+ }
+
+ const char *level_str[ECORDOVA_CONSOLE_LOGGERLEVEL_LAST] = {
+ [ECORDOVA_CONSOLE_LOGGERLEVEL_LOG] = "",
+ [ECORDOVA_CONSOLE_LOGGERLEVEL_ERROR] = "ERROR: ",
+ [ECORDOVA_CONSOLE_LOGGERLEVEL_WARN] = "WARN: ",
+ [ECORDOVA_CONSOLE_LOGGERLEVEL_INFO] = "INFO: ",
+ [ECORDOVA_CONSOLE_LOGGERLEVEL_DEBUG] = "DEBUG: ",
+ };
+
+ if (pd->console_use)
+ printf("%s%s\n", level_str[level], message);
+}
+
+#include "ecordova_console.eo.c"
diff --git a/src/lib/ecordova/ecordova_console.eo b/src/lib/ecordova/ecordova_console.eo
new file mode 100644
index 0000000000..208f3f961c
--- /dev/null
+++ b/src/lib/ecordova/ecordova_console.eo
@@ -0,0 +1,106 @@
+enum Ecordova.Console.LoggerLevel {
+ [[Logging levels]]
+ LOG,
+ ERROR,
+ WARN,
+ INFO,
+ DEBUG,
+ LAST
+}
+
+class Ecordova.Console (Eo.Base) {
+ [[Ecordova Console Plugin
+ Plugin ID: org.apache.cordova.console
+ http://plugins.cordova.io/#/package/org.apache.cordova.console
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_Console constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ }
+ log {
+ [[Logs a message at the LOG level.]]
+ params {
+ message: const(char)*; [[The log message]]
+ }
+ }
+ error {
+ [[Logs a message at the ERROR level.]]
+ params {
+ message: const(char)*; [[The log message]]
+ }
+ }
+ warn {
+ [[Logs a message at the WARN level.]]
+ params {
+ message: const(char)*; [[The log message]]
+ }
+ }
+ info {
+ [[Logs a message at the INFO level.]]
+ params {
+ message: const(char)*; [[The log message]]
+ }
+ }
+ debug {
+ [[Logs a message at the DEBUG level.]]
+ params {
+ message: const(char)*; [[The log message]]
+ }
+ }
+ @property level {
+ [[Getter/Setter for the logging level
+
+ Returns the current logging level.
+
+ When a value is passed, sets the logging level to that value.
+ The values should be one of the following constants:
+ CONSOLE_LOGGER_LEVEL_LOG
+ CONSOLE_LOGGER_LEVEL_ERROR
+ CONSOLE_LOGGER_LEVEL_WARN
+ CONSOLE_LOGGER_LEVEL_INFO
+ CONSOLE_LOGGER_LEVEL_DEBUG
+
+ The value used determines which messages get printed. The logging
+ values above are in order, and only messages logged at the logging
+ level or above will actually be displayed to the user. E.g., the
+ default level is WARN, so only messages logged with LOG, ERROR, or
+ WARN will be displayed; INFO and DEBUG messages will be ignored.
+ ]]
+ values {
+ value: Ecordova.Console.LoggerLevel; [[A valid logger level]]
+ }
+ }
+ @property console_use {
+ [[Getter/Setter for the console_use functionality
+
+ When console_use is true, the logger will log via the
+ browser 'console' object.
+ ]]
+ values {
+ value: bool; [[$EINA_TRUE to enable console output]]
+ }
+ }
+ @property logger_use {
+ [[Getter/Setter for the logger_use functionality
+
+ When logger_use is true, the logger will log via the
+ native Logger plugin.
+ ]]
+ values {
+ value: bool; [[$EINA_TRUE to enable logger output]]
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_console_private.h b/src/lib/ecordova/ecordova_console_private.h
new file mode 100644
index 0000000000..178e60b966
--- /dev/null
+++ b/src/lib/ecordova/ecordova_console_private.h
@@ -0,0 +1,20 @@
+#ifndef _ECORDOVA_CONSOLE_PRIVATE_H
+#define _ECORDOVA_CONSOLE_PRIVATE_H
+
+#include "ecordova_private.h"
+#include "ecordova_console.eo.h"
+
+typedef struct _Ecordova_Console_Data Ecordova_Console_Data;
+
+/**
+ * Ecordova.Console private data
+ */
+struct _Ecordova_Console_Data
+{
+ Eo *obj;
+ Ecordova_Console_LoggerLevel level;
+ Eina_Bool console_use;
+ Eina_Bool logger_use;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_contact.c b/src/lib/ecordova/ecordova_contact.c
new file mode 100644
index 0000000000..9b986c09e5
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contact.c
@@ -0,0 +1,1117 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_contact_private.h"
+
+#include "ecordova_contactname_private.h"
+#include "ecordova_contactfield_private.h"
+#include "ecordova_contacts_record_utils.h"
+#include "ecordova_contactaddress_private.h"
+#include "ecordova_contactorganization_private.h"
+
+#include <contacts.h>
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define MY_CLASS ECORDOVA_CONTACT_CLASS
+#define MY_CLASS_NAME "Ecordova_Contact"
+
+static Ecordova_ContactName *_contactname_copy(Ecordova_ContactName *);
+static Eina_Array *_contactfield_array_copy(Eina_Array *);
+static Eina_Array *_contactaddress_array_copy(Eina_Array *);
+static Eina_Array *_contactorganization_array_copy(Eina_Array *);
+static void _contactfield_array_free(Eina_Array *);
+static void _contactaddress_array_free(Eina_Array *);
+static void _contactorganization_array_free(Eina_Array *);
+static bool _ecordova_contactfields_import(Eina_Array *, contacts_record_h, const Ecordova_ContactField_Metadata);
+static bool _ecordova_contactfields_export(Eina_Array *, contacts_record_h, const Ecordova_ContactField_Metadata);
+static bool _ecordova_contactaddresses_import(Eina_Array *, contacts_record_h);
+static bool _ecordova_contactaddresses_export(Eina_Array *, contacts_record_h);
+static bool _ecordova_contactorganizations_import(Eina_Array *, contacts_record_h);
+static bool _ecordova_contactorganizations_export(Eina_Array *, contacts_record_h);
+static void _contactfield_array_clear_id(Eina_Array *);
+static void _contactaddress_array_clear_id(Eina_Array *);
+static void _contactorganization_array_clear_id(Eina_Array *);
+
+static Eo_Base *
+_ecordova_contact_eo_base_constructor(Eo *obj, Ecordova_Contact_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->record = NULL;
+ int ret = contacts_record_create(_contacts_contact._uri, &pd->record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, NULL);
+ pd->name = eo_add(ECORDOVA_CONTACTNAME_CLASS, NULL);
+ pd->phone_numbers = eina_array_new(1);
+ pd->emails = eina_array_new(1);
+ pd->addresses = eina_array_new(1);
+ pd->ims = eina_array_new(1);
+ pd->organizations = eina_array_new(1);
+ pd->photos = eina_array_new(1);
+ pd->categories = eina_array_new(1);
+ pd->urls = eina_array_new(1);
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_contact_eo_base_destructor(Eo *obj, Ecordova_Contact_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ eo_unref(pd->name);
+ _contactfield_array_free(pd->phone_numbers);
+ _contactfield_array_free(pd->emails);
+ _contactaddress_array_free(pd->addresses);
+ _contactfield_array_free(pd->ims);
+ _contactorganization_array_free(pd->organizations);
+ _contactfield_array_free(pd->photos);
+ _contactfield_array_free(pd->categories);
+ _contactfield_array_free(pd->urls);
+
+ int ret = contacts_record_destroy(pd->record, true);
+ EINA_SAFETY_ON_FALSE_RETURN(CONTACTS_ERROR_NONE == ret);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_contact_remove(Eo *obj, Ecordova_Contact_Data *pd)
+{
+ if (!pd->id)
+ {
+ ERR("%s", "No id");
+ goto on_error;
+ }
+
+ int ret = contacts_db_delete_record(_contacts_contact._uri, pd->id);
+ if (CONTACTS_ERROR_NONE != ret)
+ {
+ ERR("Error deleting record id: %d", pd->id);
+ goto on_error;
+ }
+
+ eo_do(obj, eo_event_callback_call(ECORDOVA_CONTACT_EVENT_REMOVE_SUCCESS, NULL));
+ return;
+
+on_error:
+ eo_do(obj, eo_event_callback_call(ECORDOVA_CONTACT_EVENT_ERROR, NULL));
+}
+
+static Ecordova_Contact *
+_ecordova_contact_clone(Eo *obj EINA_UNUSED, Ecordova_Contact_Data *pd)
+{
+ Ecordova_Contact *cloned = eo_add(ECORDOVA_CONTACTNAME_CLASS, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(cloned, NULL);
+
+ if (!ecordova_contact_export(obj, pd->record))
+ goto on_error;
+
+ if (!ecordova_contact_import(cloned, pd->record))
+ goto on_error;
+
+ Ecordova_Contact_Data *cloned_pd = eo_data_scope_get(cloned, ECORDOVA_CONTACT_CLASS);
+ EINA_SAFETY_ON_NULL_GOTO(cloned_pd, on_error);
+
+ cloned_pd->id = 0;
+ _contactfield_array_clear_id(pd->phone_numbers);
+ _contactfield_array_clear_id(pd->emails);
+ _contactaddress_array_clear_id(pd->addresses);
+ _contactfield_array_clear_id(pd->ims);
+ _contactorganization_array_clear_id(pd->organizations);
+ _contactfield_array_clear_id(pd->photos);
+ _contactfield_array_clear_id(pd->categories);
+ _contactfield_array_clear_id(pd->urls);
+
+ return cloned;
+
+on_error:
+ eo_unref(cloned);
+ return NULL;
+}
+
+static void
+_ecordova_contact_save(Eo *obj, Ecordova_Contact_Data *pd)
+{
+ int ret;
+
+ // TODO: export records in a background thread
+ if (!ecordova_contact_export(obj, pd->record))
+ {
+ ERR("%s", "Exporting record");
+ goto on_error;
+ }
+
+ if (pd->id)
+ {
+ ret = contacts_db_update_record(pd->record);
+
+ if (CONTACTS_ERROR_NONE != ret)
+ {
+ ERR("Error updating record: %d", ret);
+ goto on_error;
+ }
+ }
+ else
+ {
+ ret = contacts_db_insert_record(pd->record, &pd->id);
+ if (CONTACTS_ERROR_NONE != ret)
+ {
+ ERR("Error inserting record: %d", ret);
+ goto on_error;
+ }
+
+ // must get the inserted record so we can properly update it further
+ contacts_record_h contacts_record = NULL;
+ ret = contacts_db_get_record(_contacts_contact._uri, pd->id, &contacts_record);
+ if (CONTACTS_ERROR_NONE != ret)
+ {
+ ERR("Error getting record: %d", ret);
+ goto on_error;
+ }
+
+ ret = contacts_record_destroy(pd->record, true);
+ if (CONTACTS_ERROR_NONE != ret)
+ {
+ ERR("Error destroying record: %d", ret);
+ goto on_error;
+ }
+
+ pd->record = contacts_record;
+ }
+
+ // TODO: Check if it's necessary to update children records
+
+ eo_do(obj, eo_event_callback_call(ECORDOVA_CONTACT_EVENT_SAVE_SUCCESS, NULL));
+ return;
+
+on_error:
+ eo_do(obj, eo_event_callback_call(ECORDOVA_CONTACT_EVENT_ERROR, NULL));
+}
+
+static int
+_ecordova_contact_id_get(Eo *obj EINA_UNUSED, Ecordova_Contact_Data *pd)
+{
+ return pd->id;
+}
+
+static const char *
+_ecordova_contact_display_name_get(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd)
+{
+ const char *value = NULL;
+ get_str_p(pd->record, _contacts_contact.display_name, &value);
+ return value;
+}
+
+static void
+_ecordova_contact_display_name_set(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd,
+ const char *value)
+{
+ set_str(pd->record, _contacts_contact.display_name, value);
+}
+
+static Ecordova_ContactName *
+_ecordova_contact_name_get(Eo *obj EINA_UNUSED, Ecordova_Contact_Data *pd)
+{
+ return pd->name;
+}
+
+static void
+_ecordova_contact_name_set(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd,
+ Ecordova_ContactName *name)
+{
+ if (pd->name) eo_unref(pd->name);
+ pd->name = _contactname_copy(name);
+}
+
+static const char *
+_ecordova_contact_nickname_get(Eo *obj EINA_UNUSED, Ecordova_Contact_Data *pd)
+{
+ int ret;
+ int count = 0;
+ ret = contacts_record_get_child_record_count(pd->record,
+ _contacts_contact.nickname,
+ &count);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, NULL);
+
+ if (0 == count) return NULL;
+
+ contacts_record_h child_record = NULL;
+ ret = contacts_record_get_child_record_at_p(pd->record,
+ _contacts_contact.nickname,
+ 0,
+ &child_record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, NULL);
+
+ const char *value = NULL;
+ get_str_p(child_record, _contacts_nickname.name, &value);
+ return value;
+}
+
+static void
+_ecordova_contact_nickname_set(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd,
+ const char *value)
+{
+ int ret;
+ contacts_record_h child_record = NULL;
+ ret = contacts_record_create(_contacts_nickname._uri, &child_record);
+ EINA_SAFETY_ON_FALSE_RETURN(CONTACTS_ERROR_NONE == ret);
+
+ if (!set_str(child_record, _contacts_nickname.name, value))
+ goto on_error;
+
+ if (!clear_all_contact_record(pd->record, _contacts_contact.nickname))
+ goto on_error;
+
+ ret = contacts_record_add_child_record(pd->record,
+ _contacts_contact.nickname,
+ child_record);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error);
+ return;
+
+on_error:
+ ret = contacts_record_destroy(child_record, true);
+ EINA_SAFETY_ON_FALSE_RETURN(CONTACTS_ERROR_NONE == ret);
+}
+
+static Eina_Array *
+_ecordova_contact_phone_numbers_get(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd)
+{
+ return pd->phone_numbers;
+}
+
+static void
+_ecordova_contact_phone_numbers_set(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd,
+ Eina_Array *phone_numbers)
+{
+ _contactfield_array_free(pd->phone_numbers);
+ pd->phone_numbers = _contactfield_array_copy(phone_numbers);
+}
+
+static Eina_Array *
+_ecordova_contact_emails_get(Eo *obj EINA_UNUSED, Ecordova_Contact_Data *pd)
+{
+ return pd->emails;
+}
+
+static void
+_ecordova_contact_emails_set(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd,
+ Eina_Array *emails)
+{
+ _contactfield_array_free(pd->emails);
+ pd->emails = _contactfield_array_copy(emails);
+}
+
+static Eina_Array *
+_ecordova_contact_addresses_get(Eo *obj EINA_UNUSED, Ecordova_Contact_Data *pd)
+{
+ return pd->addresses;
+}
+
+static void
+_ecordova_contact_addresses_set(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd,
+ Eina_Array *addresses)
+{
+ _contactaddress_array_free(pd->addresses);
+ pd->addresses = _contactaddress_array_copy(addresses);
+}
+
+static Eina_Array *
+_ecordova_contact_ims_get(Eo *obj EINA_UNUSED, Ecordova_Contact_Data *pd)
+{
+ return pd->ims;
+}
+
+static void
+_ecordova_contact_ims_set(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd,
+ Eina_Array *ims)
+{
+ _contactfield_array_free(pd->ims);
+ pd->ims = _contactfield_array_copy(ims);
+}
+
+static Eina_Array *
+_ecordova_contact_organizations_get(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd)
+{
+ return pd->organizations;
+}
+
+static void
+_ecordova_contact_organizations_set(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd,
+ Eina_Array *organizations)
+{
+ _contactorganization_array_free(pd->organizations);
+ pd->organizations = _contactorganization_array_copy(organizations);
+}
+
+static time_t
+_ecordova_contact_birthday_get(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd EINA_UNUSED)
+{
+ // TODO: get birthday
+ return 0;
+}
+
+static void
+_ecordova_contact_birthday_set(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd EINA_UNUSED,
+ time_t birthday EINA_UNUSED)
+{
+ // TODO: set birthday
+}
+
+static const char *
+_ecordova_contact_note_get(Eo *obj EINA_UNUSED, Ecordova_Contact_Data *pd)
+{
+ int ret;
+ int count = 0;
+ ret = contacts_record_get_child_record_count(pd->record,
+ _contacts_contact.note,
+ &count);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, NULL);
+
+ if (0 == count)
+ return NULL;
+
+ contacts_record_h child_record = NULL;
+ ret = contacts_record_get_child_record_at_p(pd->record,
+ _contacts_contact.note,
+ 0,
+ &child_record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, NULL);
+
+ const char *value = NULL;
+ get_str_p(child_record, _contacts_note.note, &value);
+ return value;
+}
+
+static void
+_ecordova_contact_note_set(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd,
+ const char *value)
+{
+ int ret;
+ contacts_record_h child_record = NULL;
+ ret = contacts_record_create(_contacts_note._uri, &child_record);
+ EINA_SAFETY_ON_FALSE_RETURN(CONTACTS_ERROR_NONE == ret);
+
+ if (!set_str(child_record, _contacts_note.note, value))
+ goto on_error;
+
+ if (!clear_all_contact_record(pd->record, _contacts_contact.note))
+ goto on_error;
+
+ ret = contacts_record_add_child_record(pd->record,
+ _contacts_contact.note,
+ child_record);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error);
+ return;
+
+on_error:
+ ret = contacts_record_destroy(child_record, true);
+ EINA_SAFETY_ON_FALSE_RETURN(CONTACTS_ERROR_NONE == ret);
+}
+
+static Eina_Array *
+_ecordova_contact_photos_get(Eo *obj EINA_UNUSED, Ecordova_Contact_Data *pd)
+{
+ return pd->photos;
+}
+
+static void
+_ecordova_contact_photos_set(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd,
+ Eina_Array *photos)
+{
+ _contactfield_array_free(pd->photos);
+ pd->photos = _contactfield_array_copy(photos);
+}
+
+static Eina_Array *
+_ecordova_contact_categories_get(Eo *obj EINA_UNUSED, Ecordova_Contact_Data *pd)
+{
+ return pd->categories;
+}
+
+static void
+_ecordova_contact_categories_set(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd,
+ Eina_Array *categories)
+{
+ _contactfield_array_free(pd->categories);
+ pd->categories = _contactfield_array_copy(categories);
+}
+
+static Eina_Array *
+_ecordova_contact_urls_get(Eo *obj EINA_UNUSED, Ecordova_Contact_Data *pd)
+{
+ return pd->urls;
+}
+
+static void
+_ecordova_contact_urls_set(Eo *obj EINA_UNUSED,
+ Ecordova_Contact_Data *pd,
+ Eina_Array *urls)
+{
+ _contactfield_array_free(pd->urls);
+ pd->urls = _contactfield_array_copy(urls);
+}
+
+static Ecordova_ContactName *
+_contactname_copy(Ecordova_ContactName *name)
+{
+ if (!name)
+ return eo_add(ECORDOVA_CONTACTNAME_CLASS, NULL);
+
+ return ecordova_contactname_clone(name);
+}
+
+static Ecordova_ContactAddress *
+_contactaddress_copy(Ecordova_ContactAddress *address)
+{
+ if (!address)
+ return NULL;
+
+ Eina_Bool pref = EINA_FALSE;
+ const char *type = NULL;
+ const char *formatted = NULL;
+ const char *street_address = NULL;
+ const char *locality = NULL;
+ const char *region = NULL;
+ const char *postal_code = NULL;
+ const char *country = NULL;
+ eo_do(address,
+ pref = ecordova_contactaddress_pref_get(),
+ type = ecordova_contactaddress_type_get(),
+ formatted = ecordova_contactaddress_formatted_get(),
+ street_address = ecordova_contactaddress_street_address_get(),
+ locality = ecordova_contactaddress_locality_get(),
+ region = ecordova_contactaddress_region_get(),
+ postal_code = ecordova_contactaddress_postal_code_get(),
+ country = ecordova_contactaddress_country_get());
+
+ return eo_add(ECORDOVA_CONTACTADDRESS_CLASS,
+ NULL,
+ ecordova_contactaddress_constructor(pref,
+ type,
+ formatted,
+ street_address,
+ locality,
+ region,
+ postal_code,
+ country));
+}
+
+static Ecordova_ContactField *
+_contactfield_copy(Ecordova_ContactField *field)
+{
+ if (!field)
+ return NULL;
+
+ const char *type = NULL;
+ const char *value = NULL;
+ Eina_Bool pref = EINA_FALSE;
+ eo_do(field,
+ type = ecordova_contactfield_type_get(),
+ value = ecordova_contactfield_value_get(),
+ pref = ecordova_contactfield_pref_get());
+
+ return eo_add(ECORDOVA_CONTACTFIELD_CLASS, NULL,
+ ecordova_contactfield_constructor(type, value, pref));
+}
+
+static Ecordova_ContactOrganization *
+_contactorganization_copy(Ecordova_ContactOrganization *organization)
+{
+ if (!organization)
+ return NULL;
+
+ Eina_Bool pref = EINA_FALSE;
+ const char *type = NULL;
+ const char *name = NULL;
+ const char *dept = NULL;
+ const char *title = NULL;
+ eo_do(organization,
+ pref = ecordova_contactorganization_pref_get(),
+ type = ecordova_contactorganization_type_get(),
+ name = ecordova_contactorganization_name_get(),
+ dept = ecordova_contactorganization_dept_get(),
+ title = ecordova_contactorganization_title_get());
+
+ return eo_add(ECORDOVA_CONTACTORGANIZATION_CLASS,
+ NULL,
+ ecordova_contactorganization_constructor(pref,
+ type,
+ name,
+ dept,
+ title));
+}
+
+static Eina_Array *
+_contactfield_array_copy(Eina_Array *fields)
+{
+ Eina_Array *result = eina_array_new(1);
+ if (!fields)
+ return result;
+
+ size_t i;
+ Ecordova_ContactField *field;
+ Eina_Array_Iterator it;
+ EINA_ARRAY_ITER_NEXT(fields, i, field, it)
+ eina_array_push(result, _contactfield_copy(field));
+ return result;
+}
+
+static Eina_Array *
+_contactaddress_array_copy(Eina_Array *addresses)
+{
+ Eina_Array *result = eina_array_new(1);
+ if (!addresses)
+ return result;
+
+ size_t i;
+ Ecordova_ContactAddress *address;
+ Eina_Array_Iterator it;
+ EINA_ARRAY_ITER_NEXT(addresses, i, address, it)
+ eina_array_push(result, _contactaddress_copy(address));
+ return result;
+}
+
+static Eina_Array *
+_contactorganization_array_copy(Eina_Array *organizations)
+{
+ Eina_Array *result = eina_array_new(1);
+ if (!organizations)
+ return result;
+
+ size_t i;
+ Ecordova_ContactOrganization *organization;
+ Eina_Array_Iterator it;
+ EINA_ARRAY_ITER_NEXT(organizations, i, organization, it)
+ eina_array_push(result, _contactorganization_copy(organization));
+ return result;
+}
+
+static void
+_contactfield_array_free(Eina_Array *fields)
+{
+ if (!fields)
+ return;
+
+ size_t i;
+ Ecordova_ContactField *field;
+ Eina_Array_Iterator it;
+ EINA_ARRAY_ITER_NEXT(fields, i, field, it)
+ eo_unref(field);
+ eina_array_free(fields);
+}
+
+static void
+_contactaddress_array_free(Eina_Array *addresses)
+{
+ if (!addresses)
+ return;
+
+ size_t i;
+ Ecordova_ContactAddress *address;
+ Eina_Array_Iterator it;
+ EINA_ARRAY_ITER_NEXT(addresses, i, address, it)
+ eo_unref(address);
+ eina_array_free(addresses);
+}
+
+static void
+_contactorganization_array_free(Eina_Array *organizations)
+{
+ if (!organizations)
+ return;
+
+ size_t i;
+ Ecordova_ContactOrganization *organization;
+ Eina_Array_Iterator it;
+ EINA_ARRAY_ITER_NEXT(organizations, i, organization, it)
+ eo_unref(organization);
+ eina_array_free(organizations);
+}
+
+static void
+_contactfield_array_clear_id(Eina_Array *fields)
+{
+ if (!fields)
+ return;
+
+ size_t i;
+ Ecordova_ContactField *field;
+ Eina_Array_Iterator it;
+ EINA_ARRAY_ITER_NEXT(fields, i, field, it)
+ {
+ Ecordova_ContactField_Data *pd =
+ eo_data_scope_get(field, ECORDOVA_CONTACTFIELD_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN(pd);
+
+ pd->id = 0;
+ }
+}
+
+static void
+_contactaddress_array_clear_id(Eina_Array *addresses)
+{
+ if (!addresses)
+ return;
+
+ size_t i;
+ Ecordova_ContactAddress *address;
+ Eina_Array_Iterator it;
+ EINA_ARRAY_ITER_NEXT(addresses, i, address, it)
+ {
+ Ecordova_ContactAddress_Data *pd =
+ eo_data_scope_get(address, ECORDOVA_CONTACTADDRESS_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN(pd);
+
+ pd->id = 0;
+ }
+}
+
+static void
+_contactorganization_array_clear_id(Eina_Array *organizations)
+{
+ if (!organizations)
+ return;
+
+ size_t i;
+ Ecordova_ContactOrganization *organization;
+ Eina_Array_Iterator it;
+ EINA_ARRAY_ITER_NEXT(organizations, i, organization, it)
+ {
+ Ecordova_ContactOrganization_Data *pd =
+ eo_data_scope_get(organization, ECORDOVA_CONTACTORGANIZATION_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN(pd);
+
+ pd->id = 0;
+ }
+}
+
+static const Ecordova_ContactField_Metadata
+_contact_number_metadata = {
+ .uri = &_contacts_number._uri,
+ .ids = {
+ [ECORDOVA_CONTACTFIELD_PARENT_PROPERTY_ID] = &_contacts_contact.number,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_ID] = &_contacts_number.id,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_TYPE] = &_contacts_number.type,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_LABEL] = &_contacts_number.label,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_VALUE] = &_contacts_number.number,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_PREF] = &_contacts_number.is_default},
+ .type2label = ecordova_contactnumber_type2label,
+ .label2type = ecordova_contactnumber_label2type
+};
+
+static const Ecordova_ContactField_Metadata
+_contact_email_metadata = {
+ .uri = &_contacts_email._uri,
+ .ids = {
+ [ECORDOVA_CONTACTFIELD_PARENT_PROPERTY_ID] = &_contacts_contact.email,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_ID] = &_contacts_email.id,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_TYPE] = &_contacts_email.type,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_LABEL] = &_contacts_email.label,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_VALUE] = &_contacts_email.email,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_PREF] = &_contacts_email.is_default},
+ .type2label = ecordova_contactemail_type2label,
+ .label2type = ecordova_contactemail_label2type
+};
+
+static const Ecordova_ContactField_Metadata
+_contact_messenger_metadata = {
+ .uri = &_contacts_messenger._uri,
+ .ids = {
+ [ECORDOVA_CONTACTFIELD_PARENT_PROPERTY_ID] = &_contacts_contact.messenger,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_ID] = &_contacts_messenger.id,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_TYPE] = &_contacts_messenger.type,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_LABEL] = &_contacts_messenger.label,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_VALUE] = &_contacts_messenger.im_id,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_PREF] = NULL},
+ .type2label = ecordova_contactmessenger_type2label,
+ .label2type = ecordova_contactmessenger_label2type
+};
+
+static const Ecordova_ContactField_Metadata
+_contact_image_metadata = {
+ .uri = &_contacts_image._uri,
+ .ids = {
+ [ECORDOVA_CONTACTFIELD_PARENT_PROPERTY_ID] = &_contacts_contact.image,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_ID] = &_contacts_image.id,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_TYPE] = &_contacts_image.type,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_LABEL] = &_contacts_image.label,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_VALUE] = &_contacts_image.path,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_PREF] = &_contacts_image.is_default},
+ .type2label = ecordova_contactimage_type2label,
+ .label2type = ecordova_contactimage_label2type
+};
+
+static const Ecordova_ContactField_Metadata
+_contact_url_metadata = {
+ .uri = &_contacts_url._uri,
+ .ids = {
+ [ECORDOVA_CONTACTFIELD_PARENT_PROPERTY_ID] = &_contacts_contact.url,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_ID] = &_contacts_url.id,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_TYPE] = &_contacts_url.type,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_LABEL] = &_contacts_url.label,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_VALUE] = &_contacts_url.url,
+ [ECORDOVA_CONTACTFIELD_PROPERTY_PREF] = NULL},
+ .type2label = ecordova_contacturl_type2label,
+ .label2type = ecordova_contacturl_label2type
+};
+
+bool
+ecordova_contact_import(Ecordova_Contact *obj,
+ contacts_record_h contacts_record)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(obj, false);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(contacts_record, false);
+
+ Ecordova_Contact_Data *pd = eo_data_scope_get(obj, ECORDOVA_CONTACT_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pd, false);
+
+ int ret;
+
+ ret = contacts_record_destroy(pd->record, true);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+ ret = contacts_record_clone(contacts_record, &pd->record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ ret = contacts_record_get_int(pd->record, _contacts_contact.id, &pd->id);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ // name
+ DBG("%s", "Importing name");
+ if (!ecordova_contactname_import(pd->name, pd->record))
+ return false;
+
+ // phone_numbers
+ DBG("%s", "Importing phone_numbers");
+ if (!_ecordova_contactfields_import(pd->phone_numbers,
+ pd->record,
+ _contact_number_metadata))
+ return false;
+
+ // emails
+ DBG("%s", "Importing emails");
+ if (!_ecordova_contactfields_import(pd->emails,
+ pd->record,
+ _contact_email_metadata))
+ return false;
+
+ // addresses
+ DBG("%s", "Importing addresses");
+ if (!_ecordova_contactaddresses_import(pd->addresses, pd->record))
+ return false;
+
+ // ims
+ DBG("%s", "Importing ims");
+ if (!_ecordova_contactfields_import(pd->ims,
+ pd->record,
+ _contact_messenger_metadata))
+ return false;
+
+ // organizations
+ DBG("%s", "Importing organizations");
+ if (!_ecordova_contactorganizations_import(pd->organizations, pd->record))
+ return false;
+
+ // photos
+ DBG("%s", "Importing photos");
+ if (!_ecordova_contactfields_import(pd->photos,
+ pd->record,
+ _contact_image_metadata))
+ return false;
+
+ // TODO: categories
+
+ // urls
+ DBG("%s", "Importing urls");
+ if (!_ecordova_contactfields_import(pd->urls,
+ pd->record,
+ _contact_url_metadata))
+ return false;
+
+ return true;
+}
+
+bool
+ecordova_contact_export(Ecordova_Contact *obj,
+ contacts_record_h contacts_record)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(obj, false);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(contacts_record, false);
+
+ Ecordova_Contact_Data *pd = eo_data_scope_get(obj, ECORDOVA_CONTACT_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pd, false);
+
+ // name
+ if (!clear_all_contact_record(contacts_record, _contacts_contact.name) ||
+ !ecordova_contactname_export(pd->name, contacts_record))
+ return false;
+
+ // phone_numbers
+ if (!_ecordova_contactfields_export(pd->phone_numbers,
+ contacts_record,
+ _contact_number_metadata))
+ return false;
+
+ // emails
+ if (!_ecordova_contactfields_export(pd->emails,
+ contacts_record,
+ _contact_email_metadata))
+ return false;
+
+ // addresses
+ if (!_ecordova_contactaddresses_export(pd->addresses, contacts_record))
+ return false;
+
+ // ims
+ if (!_ecordova_contactfields_export(pd->ims,
+ contacts_record,
+ _contact_messenger_metadata))
+ return false;
+
+ // organizations
+ if (!_ecordova_contactorganizations_export(pd->organizations, contacts_record))
+ return false;
+
+ // photos
+ if (!_ecordova_contactfields_export(pd->photos,
+ contacts_record,
+ _contact_image_metadata))
+ return false;
+
+ // TODO: categories
+
+ // urls
+ if (!_ecordova_contactfields_export(pd->urls,
+ contacts_record,
+ _contact_url_metadata))
+ return false;
+
+ return true;
+}
+
+static bool
+_ecordova_contactfields_import(Eina_Array *fields,
+ contacts_record_h contacts_record,
+ const Ecordova_ContactField_Metadata metadata)
+{
+ int ret;
+ int count = 0;
+ ret = contacts_record_get_child_record_count(contacts_record,
+ *metadata.ids[ECORDOVA_CONTACTFIELD_PARENT_PROPERTY_ID],
+ &count);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ DBG("Importing %d children", count);
+ for (int index = 0; index < count; ++index)
+ {
+ contacts_record_h child_record = NULL;
+ ret = contacts_record_get_child_record_at_p(contacts_record,
+ *metadata.ids[ECORDOVA_CONTACTFIELD_PARENT_PROPERTY_ID],
+ index,
+ &child_record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ Ecordova_ContactField *field = eo_add(ECORDOVA_CONTACTFIELD_CLASS, NULL);
+ if (!ecordova_contactfield_import(field, child_record, metadata))
+ {
+ eo_unref(field);
+ return false;
+ }
+
+ Eina_Bool ret = eina_array_push(fields, field);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ret, false);
+ }
+
+ return true;
+}
+
+static bool
+_ecordova_contactfields_export(Eina_Array *fields,
+ contacts_record_h contacts_record,
+ const Ecordova_ContactField_Metadata metadata)
+{
+ if (!clear_all_contact_record(contacts_record,
+ *metadata.ids[ECORDOVA_CONTACTFIELD_PARENT_PROPERTY_ID]))
+ return false;
+
+ Ecordova_ContactField *field;
+ Eina_Array_Iterator iterator;
+ unsigned int i;
+ EINA_ARRAY_ITER_NEXT(fields, i, field, iterator)
+ {
+ contacts_record_h record = NULL;
+ int ret = contacts_record_create(*metadata.uri, &record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ if (!ecordova_contactfield_export(field, record, metadata))
+ {
+ ret = contacts_record_destroy(record, true);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+ return false;
+ }
+
+ ret = contacts_record_add_child_record(contacts_record,
+ *metadata.ids[ECORDOVA_CONTACTFIELD_PARENT_PROPERTY_ID],
+ record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+ }
+
+ return true;
+}
+
+static bool
+_ecordova_contactaddresses_import(Eina_Array *fields,
+ contacts_record_h contacts_record)
+{
+ int ret;
+ int count = 0;
+ ret = contacts_record_get_child_record_count(contacts_record,
+ _contacts_contact.address,
+ &count);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ DBG("Importing %d addresses", count);
+ for (int index = 0; index < count; ++index)
+ {
+ contacts_record_h child_record = NULL;
+ ret = contacts_record_get_child_record_at_p(contacts_record,
+ _contacts_contact.address,
+ index,
+ &child_record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ Ecordova_ContactAddress *address = eo_add(ECORDOVA_CONTACTADDRESS_CLASS, NULL);
+ if (!ecordova_contactaddress_import(address, child_record))
+ {
+ eo_unref(address);
+ return false;
+ }
+
+ Eina_Bool ret = eina_array_push(fields, address);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ret, false);
+ }
+
+ return true;
+}
+
+static bool
+_ecordova_contactaddresses_export(Eina_Array *addresses,
+ contacts_record_h contacts_record)
+{
+ if (!clear_all_contact_record(contacts_record, _contacts_contact.address))
+ return false;
+
+ Ecordova_ContactAddress *address;
+ Eina_Array_Iterator iterator;
+ unsigned int i;
+ EINA_ARRAY_ITER_NEXT(addresses, i, address, iterator)
+ {
+ contacts_record_h record = NULL;
+ int ret = contacts_record_create(_contacts_address._uri, &record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ if (!ecordova_contactaddress_export(address, record))
+ {
+ ret = contacts_record_destroy(record, true);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+ return false;
+ }
+
+ ret = contacts_record_add_child_record(contacts_record,
+ _contacts_contact.address,
+ record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+ }
+
+ return true;
+}
+
+static bool
+_ecordova_contactorganizations_import(Eina_Array *organizations,
+ contacts_record_h contacts_record)
+{
+ int ret;
+ int count = 0;
+ ret = contacts_record_get_child_record_count(contacts_record,
+ _contacts_contact.company,
+ &count);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ DBG("Importing %d organizations", count);
+ for (int index = 0; index < count; ++index)
+ {
+ contacts_record_h child_record = NULL;
+ ret = contacts_record_get_child_record_at_p(contacts_record,
+ _contacts_contact.company,
+ index,
+ &child_record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ Ecordova_ContactOrganization *organization = eo_add(ECORDOVA_CONTACTORGANIZATION_CLASS, NULL);
+ if (!ecordova_contactorganization_import(organization, child_record))
+ {
+ eo_unref(organization);
+ return false;
+ }
+
+ Eina_Bool ret = eina_array_push(organizations, organization);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ret, false);
+ }
+
+ return true;
+}
+
+static bool
+_ecordova_contactorganizations_export(Eina_Array *organizations,
+ contacts_record_h contacts_record)
+{
+ if (!clear_all_contact_record(contacts_record, _contacts_contact.company))
+ return false;
+
+ Ecordova_ContactOrganization *organization;
+ Eina_Array_Iterator iterator;
+ unsigned int i;
+ EINA_ARRAY_ITER_NEXT(organizations, i, organization, iterator)
+ {
+ contacts_record_h record = NULL;
+ int ret = contacts_record_create(_contacts_company._uri, &record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ if (!ecordova_contactaddress_export(organization, record))
+ {
+ ret = contacts_record_destroy(record, true);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+ return false;
+ }
+
+ ret = contacts_record_add_child_record(contacts_record,
+ _contacts_contact.company,
+ record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+ }
+
+ return true;
+}
+
+#include "ecordova_contact.eo.c"
diff --git a/src/lib/ecordova/ecordova_contact.eo b/src/lib/ecordova/ecordova_contact.eo
new file mode 100644
index 0000000000..88afe5fe34
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contact.eo
@@ -0,0 +1,98 @@
+class Ecordova.Contact (Eo.Base) {
+ [[Contains information about a single contact.]]
+ legacy_prefix: null;
+ methods {
+ remove {
+ [[Removes contact from device storage.]]
+ }
+ clone {
+ [[Creates a deep copy of this Contact. With the contact ID set to
+ null.
+ ]]
+ return: Ecordova.Contact*; [[copy of this Contact]]
+ }
+ save {
+ [[Persists contact to device storage.]]
+ }
+ @property id {
+ get {}
+ values {
+ id: int ;
+ }
+ }
+ @property display_name {
+ values {
+ display_name: const(char)*;
+ }
+ }
+ @property name {
+ values {
+ name: Ecordova.ContactName*;
+ }
+ }
+ @property nickname {
+ values {
+ nickname: const(char)*;
+ }
+ }
+ @property phone_numbers {
+ values {
+ phone_numbers: array<Ecordova.ContactField*>*;
+ }
+ }
+ @property emails {
+ values {
+ emails: array<Ecordova.ContactField*>*;
+ }
+ }
+ @property addresses {
+ values {
+ addresses: array<Ecordova.ContactAddress*>*;
+ }
+ }
+ @property ims {
+ values {
+ ims: array<Ecordova.ContactField*>*;
+ }
+ }
+ @property organizations {
+ values {
+ organizations: array<Ecordova.ContactOrganization*>*;
+ }
+ }
+ @property birthday {
+ values {
+ birthday: time ;
+ }
+ }
+ @property note {
+ values {
+ note: const(char)*;
+ }
+ }
+ @property photos {
+ values {
+ photos: array<Ecordova.ContactField*>*;
+ }
+ }
+ @property categories {
+ values {
+ categories: array<Ecordova.ContactField*>*;
+ }
+ }
+ @property urls {
+ values {
+ urls: array<Ecordova.ContactField*>*;
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ events {
+ save,success;
+ remove,success;
+ error;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_contact_private.h b/src/lib/ecordova/ecordova_contact_private.h
new file mode 100644
index 0000000000..4a1ddc8deb
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contact_private.h
@@ -0,0 +1,38 @@
+#ifndef _ECORDOVA_CONTACT_PRIVATE_H
+#define _ECORDOVA_CONTACT_PRIVATE_H
+
+#include "ecordova_private.h"
+#include "ecordova_contactaddress.eo.h"
+#include "ecordova_contactfield.eo.h"
+#include "ecordova_contactname.eo.h"
+#include "ecordova_contactorganization.eo.h"
+#include "ecordova_contact.eo.h"
+
+#include <contacts.h>
+#include <stdbool.h>
+
+typedef struct _Ecordova_Contact_Data Ecordova_Contact_Data;
+
+/**
+ * Ecordova.Contact private data
+ */
+struct _Ecordova_Contact_Data
+{
+ Eo *obj;
+ contacts_record_h record;
+ int id;
+ Ecordova_ContactName *name;
+ Eina_Array *phone_numbers;
+ Eina_Array *emails;
+ Eina_Array *addresses;
+ Eina_Array *ims;
+ Eina_Array *organizations;
+ Eina_Array *photos;
+ Eina_Array *categories;
+ Eina_Array *urls;
+};
+
+bool ecordova_contact_import(Ecordova_Contact *, contacts_record_h);
+bool ecordova_contact_export(Ecordova_Contact *, contacts_record_h);
+
+#endif
diff --git a/src/lib/ecordova/ecordova_contactaddress.c b/src/lib/ecordova/ecordova_contactaddress.c
new file mode 100644
index 0000000000..23918f2432
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contactaddress.c
@@ -0,0 +1,312 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_contactaddress_private.h"
+#include "ecordova_contacts_record_utils.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define MY_CLASS ECORDOVA_CONTACTADDRESS_CLASS
+#define MY_CLASS_NAME "Ecordova_ContactAddress"
+
+static Eo_Base *
+_ecordova_contactaddress_eo_base_constructor(Eo *obj,
+ Ecordova_ContactAddress_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->id = 0;
+ pd->record = NULL;
+ int ret = contacts_record_create(_contacts_address._uri, &pd->record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, NULL);
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_contactaddress_constructor(Eo *obj,
+ Ecordova_ContactAddress_Data *pd EINA_UNUSED,
+ Eina_Bool pref,
+ const char *type,
+ const char *formatted,
+ const char *street_address,
+ const char *locality,
+ const char *region,
+ const char *postal_code,
+ const char *country)
+{
+ DBG("(%p)", obj);
+ eo_do(obj,
+ ecordova_contactaddress_pref_set(pref),
+ ecordova_contactaddress_type_set(type),
+ ecordova_contactaddress_formatted_set(formatted),
+ ecordova_contactaddress_street_address_set(street_address),
+ ecordova_contactaddress_locality_set(locality),
+ ecordova_contactaddress_region_set(region),
+ ecordova_contactaddress_postal_code_set(postal_code),
+ ecordova_contactaddress_country_set(country));
+}
+
+static void
+_ecordova_contactaddress_eo_base_destructor(Eo *obj,
+ Ecordova_ContactAddress_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ int ret = contacts_record_destroy(pd->record, true);
+ EINA_SAFETY_ON_FALSE_RETURN(CONTACTS_ERROR_NONE == ret);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static int
+_ecordova_contactaddress_id_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd)
+{
+ return pd->id;
+}
+
+static Eina_Bool
+_ecordova_contactaddress_pref_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd)
+{
+ Eina_Bool value = EINA_FALSE;
+ get_bool(pd->record, _contacts_address.is_default, &value);
+ return value;
+}
+
+static void
+_ecordova_contactaddress_pref_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd,
+ Eina_Bool value)
+{
+ set_bool(pd->record, _contacts_address.is_default, value);
+}
+
+static const char *
+_ecordova_contactaddress_type_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd)
+{
+ int type;
+ if (!get_int(pd->record, _contacts_address.type, &type))
+ return NULL;
+
+ switch (type)
+ {
+ case CONTACTS_ADDRESS_TYPE_HOME:
+ return "Home";
+ case CONTACTS_ADDRESS_TYPE_WORK:
+ return "Work";
+ case CONTACTS_ADDRESS_TYPE_DOM:
+ return "Dom";
+ case CONTACTS_ADDRESS_TYPE_INTL:
+ return "Intl";
+ case CONTACTS_ADDRESS_TYPE_POSTAL:
+ return "Postal";
+ case CONTACTS_ADDRESS_TYPE_PARCEL:
+ return "Parcel";
+ case CONTACTS_ADDRESS_TYPE_OTHER:
+ case CONTACTS_ADDRESS_TYPE_CUSTOM:
+ default:
+ {
+ const char *custom = NULL;
+ get_str_p(pd->record, _contacts_address.label, &custom);
+ return custom;
+ }
+ }
+}
+
+static void
+_ecordova_contactaddress_type_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd,
+ const char *value)
+{
+ int type = CONTACTS_ADDRESS_TYPE_OTHER;
+ if (!value || strlen(value) == 0)
+ type = CONTACTS_ADDRESS_TYPE_OTHER;
+ else
+ if (strcasecmp(value, "Home"))
+ type = CONTACTS_ADDRESS_TYPE_HOME;
+ else if (strcasecmp(value, "Work"))
+ type = CONTACTS_ADDRESS_TYPE_WORK;
+ else if (strcasecmp(value, "Dom"))
+ type = CONTACTS_ADDRESS_TYPE_DOM;
+ else if (strcasecmp(value, "Intl"))
+ type = CONTACTS_ADDRESS_TYPE_INTL;
+ else if (strcasecmp(value, "Postal"))
+ type = CONTACTS_ADDRESS_TYPE_POSTAL;
+ else if (strcasecmp(value, "Parcel"))
+ type = CONTACTS_ADDRESS_TYPE_PARCEL;
+ else
+ type = CONTACTS_ADDRESS_TYPE_CUSTOM;
+
+ set_int(pd->record, _contacts_address.type, type);
+ if (strlen(value) != 0)
+ set_str(pd->record, _contacts_address.label, value);
+}
+
+static const char *
+_ecordova_contactaddress_formatted_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd EINA_UNUSED)
+{
+ // TODO: mount the formatted address
+ ERR("%s", "Not implemented");
+ return NULL;
+}
+
+static void
+_ecordova_contactaddress_formatted_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd EINA_UNUSED,
+ const char *formatted EINA_UNUSED)
+{
+ ERR("%s", "Not implemented");
+}
+
+static const char *
+_ecordova_contactaddress_street_address_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd)
+{
+ const char *value = NULL;
+ get_str_p(pd->record, _contacts_address.street, &value);
+ return value;
+}
+
+static void
+_ecordova_contactaddress_street_address_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd,
+ const char *value)
+{
+ set_str(pd->record, _contacts_address.street, value);
+}
+
+static const char *
+_ecordova_contactaddress_locality_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd)
+{
+ const char *value = NULL;
+ get_str_p(pd->record, _contacts_address.locality, &value);
+ return value;
+}
+
+static void
+_ecordova_contactaddress_locality_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd,
+ const char *value)
+{
+ set_str(pd->record, _contacts_address.locality, value);
+}
+
+static const char *
+_ecordova_contactaddress_region_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd)
+{
+ const char *value = NULL;
+ get_str_p(pd->record, _contacts_address.region, &value);
+ return value;
+}
+
+static void
+_ecordova_contactaddress_region_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd,
+ const char *value)
+{
+ set_str(pd->record, _contacts_address.region, value);
+}
+
+static const char *
+_ecordova_contactaddress_postal_code_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd)
+{
+ const char *value = NULL;
+ get_str_p(pd->record, _contacts_address.postal_code, &value);
+ return value;
+}
+
+static void
+_ecordova_contactaddress_postal_code_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd,
+ const char *value)
+{
+ set_str(pd->record, _contacts_address.postal_code, value);
+}
+
+static const char *
+_ecordova_contactaddress_country_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd)
+{
+ const char *value = NULL;
+ get_str_p(pd->record, _contacts_address.country, &value);
+ return value;
+}
+
+static void
+_ecordova_contactaddress_country_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactAddress_Data *pd,
+ const char *value)
+{
+ set_str(pd->record, _contacts_address.country, value);
+}
+
+bool
+ecordova_contactaddress_import(Ecordova_ContactAddress *obj,
+ contacts_record_h child_record)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(obj, false);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(child_record, false);
+
+ Ecordova_ContactAddress_Data *pd = eo_data_scope_get(obj, ECORDOVA_CONTACTADDRESS_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pd, false);
+
+ int ret = contacts_record_destroy(pd->record, true);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+ ret = contacts_record_clone(child_record, &pd->record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ return get_int(child_record, _contacts_address.id, &pd->id);
+}
+
+bool
+ecordova_contactaddress_export(Ecordova_ContactAddress *obj,
+ contacts_record_h contacts_record)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(obj, false);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(contacts_record, false);
+
+ Ecordova_ContactAddress_Data *pd = eo_data_scope_get(obj, ECORDOVA_CONTACTADDRESS_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pd, false);
+
+ contacts_record_h child_record = NULL;
+ int ret = contacts_record_clone(pd->record, &child_record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ ret = contacts_record_add_child_record(contacts_record,
+ _contacts_contact.address,
+ child_record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ return true;
+}
+
+Ecordova_ContactAddress *
+ecordova_contactaddress_clone(Ecordova_ContactAddress *other)
+{
+ Ecordova_ContactAddress *cloned = eo_add(ECORDOVA_CONTACTADDRESS_CLASS, NULL);
+
+ Ecordova_ContactAddress_Data *cloned_pd = eo_data_scope_get(cloned, ECORDOVA_CONTACTADDRESS_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(cloned_pd, NULL);
+ Ecordova_ContactAddress_Data *other_pd = eo_data_scope_get(other, ECORDOVA_CONTACTADDRESS_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(other_pd, NULL);
+
+ int ret = contacts_record_destroy(cloned_pd->record, true);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, NULL);
+ ret = contacts_record_clone(other_pd->record, &cloned_pd->record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, NULL);
+
+ return cloned;
+}
+
+#include "ecordova_contactaddress.eo.c"
diff --git a/src/lib/ecordova/ecordova_contactaddress.eo b/src/lib/ecordova/ecordova_contactaddress.eo
new file mode 100644
index 0000000000..ee5a9efef9
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contactaddress.eo
@@ -0,0 +1,93 @@
+class Ecordova.ContactAddress (Eo.Base) {
+ [[Contains information about a single contact.]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_ContactAddress constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ params {
+ pref: bool;
+ [[user's preferred value.]]
+
+ type: const(char)*;
+ [[A string indicating what type of field this is, home for
+ example.
+ ]]
+
+ formatted: const(char)*;
+ [[The full address formatted for display.]]
+
+ street_address: const(char)*;
+ [[The full street address.]]
+
+ locality: const(char)*;
+ [[The city or locality.]]
+
+ region: const(char)*;
+ [[The state or region.]]
+
+ postal_code: const(char)*;
+ [[The zip code or postal code.]]
+
+ country: const(char)*;
+ [[The country name.]]
+ }
+ }
+ @property id {
+ get {}
+ values {
+ id: int;
+ }
+ }
+ @property pref {
+ values {
+ preferred: bool;
+ }
+ }
+ @property type {
+ values {
+ type: const(char)*;
+ }
+ }
+ @property formatted {
+ values {
+ formatted: const(char)*;
+ }
+ }
+ @property street_address {
+ values {
+ street_address: const(char)*;
+ }
+ }
+ @property locality {
+ values {
+ locality: const(char)*;
+ }
+ }
+ @property region {
+ values {
+ region: const(char)*;
+ }
+ }
+ @property postal_code {
+ values {
+ postal_code: const(char)*;
+ }
+ }
+ @property country {
+ values {
+ country: const(char)*;
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_contactaddress_private.h b/src/lib/ecordova/ecordova_contactaddress_private.h
new file mode 100644
index 0000000000..56715d34f1
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contactaddress_private.h
@@ -0,0 +1,25 @@
+#ifndef _ECORDOVA_CONTACTADDRESS_PRIVATE_H
+#define _ECORDOVA_CONTACTADDRESS_PRIVATE_H
+
+#include "ecordova_private.h"
+#include "ecordova_contactaddress.eo.h"
+
+#include <contacts.h>
+
+typedef struct _Ecordova_ContactAddress_Data Ecordova_ContactAddress_Data;
+
+/**
+ * Ecordova.ContactAddress private data
+ */
+struct _Ecordova_ContactAddress_Data
+{
+ Eo *obj;
+ int id;
+ contacts_record_h record;
+};
+
+bool ecordova_contactaddress_import(Ecordova_ContactAddress *, contacts_record_h);
+bool ecordova_contactaddress_export(Ecordova_ContactAddress *, contacts_record_h);
+Ecordova_ContactAddress *ecordova_contactaddress_clone(Ecordova_ContactAddress *);
+
+#endif
diff --git a/src/lib/ecordova/ecordova_contactfield.c b/src/lib/ecordova/ecordova_contactfield.c
new file mode 100644
index 0000000000..8397a1944d
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contactfield.c
@@ -0,0 +1,415 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_contactfield_private.h"
+#include "ecordova_contacts_record_utils.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define MY_CLASS ECORDOVA_CONTACTFIELD_CLASS
+#define MY_CLASS_NAME "Ecordova_ContactField"
+
+static Eo_Base *
+_ecordova_contactfield_eo_base_constructor(Eo *obj,
+ Ecordova_ContactField_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_contactfield_constructor(Eo *obj,
+ Ecordova_ContactField_Data *pd,
+ const char *type,
+ const char *value,
+ Eina_Bool pref)
+{
+ DBG("(%p)", obj);
+ pd->id = 0;
+ pd->type = type ? strdup(type) : NULL;
+ pd->value = value ? strdup(value) : NULL;
+ pd->pref = pref;
+}
+
+static void
+_ecordova_contactfield_eo_base_destructor(Eo *obj,
+ Ecordova_ContactField_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ free(pd->type);
+ free(pd->value);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static int
+_ecordova_contactfield_id_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactField_Data *pd)
+{
+ return pd->id;
+}
+
+static const char *
+_ecordova_contactfield_type_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactField_Data *pd)
+{
+ return pd->type;
+}
+
+static void
+_ecordova_contactfield_type_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactField_Data *pd,
+ const char *type)
+{
+ free(pd->type);
+ pd->type = type ? strdup(type) : NULL;
+}
+
+static const char *
+_ecordova_contactfield_value_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactField_Data *pd)
+{
+ return pd->value;
+}
+
+static void
+_ecordova_contactfield_value_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactField_Data *pd,
+ const char *value)
+{
+ free(pd->value);
+ pd->value = value ? strdup(value) : NULL;
+}
+
+static Eina_Bool
+_ecordova_contactfield_pref_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactField_Data *pd)
+{
+ return pd->pref;
+}
+
+static void
+_ecordova_contactfield_pref_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactField_Data *pd,
+ Eina_Bool pref)
+{
+ pd->pref = pref;
+}
+
+bool
+ecordova_contactfield_import(Ecordova_ContactField *obj,
+ contacts_record_h record,
+ const Ecordova_ContactField_Metadata metadata)
+{
+ DBG("%p", obj);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(obj, false);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(record, false);
+
+ Ecordova_ContactField_Data *pd = eo_data_scope_get(obj, ECORDOVA_CONTACTFIELD_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pd, false);
+
+ int type = 0;
+ const char* label = NULL;
+ if (!get_int(record,
+ *metadata.ids[ECORDOVA_CONTACTFIELD_PROPERTY_TYPE],
+ &type) ||
+ !get_str_p(record,
+ *metadata.ids[ECORDOVA_CONTACTFIELD_PROPERTY_LABEL],
+ &label))
+ return false;
+
+ pd->type = metadata.type2label(type, label);
+
+ if (!get_int(record,
+ *metadata.ids[ECORDOVA_CONTACTFIELD_PROPERTY_ID],
+ &pd->id) ||
+ !get_str(record,
+ *metadata.ids[ECORDOVA_CONTACTFIELD_PROPERTY_VALUE],
+ &pd->value))
+ return false;
+
+ if (metadata.ids[ECORDOVA_CONTACTFIELD_PROPERTY_PREF] &&
+ !get_bool(record,
+ *metadata.ids[ECORDOVA_CONTACTFIELD_PROPERTY_PREF],
+ &pd->pref))
+ return false;
+
+ return true;
+}
+
+bool
+ecordova_contactfield_export(Ecordova_ContactField *obj,
+ contacts_record_h record,
+ const Ecordova_ContactField_Metadata metadata)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(obj, false);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(record, false);
+
+ Ecordova_ContactField_Data *pd = eo_data_scope_get(obj, ECORDOVA_CONTACTFIELD_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pd, false);
+
+ int type = metadata.label2type(pd->type);
+ if (!set_int(record,
+ *metadata.ids[ECORDOVA_CONTACTFIELD_PROPERTY_TYPE],
+ type))
+ return false;
+
+ if (pd->type &&
+ !set_str(record,
+ *metadata.ids[ECORDOVA_CONTACTFIELD_PROPERTY_LABEL],
+ pd->type))
+ return false;
+
+ if (!set_str(record,
+ *metadata.ids[ECORDOVA_CONTACTFIELD_PROPERTY_VALUE],
+ pd->value))
+ return false;
+
+ if (metadata.ids[ECORDOVA_CONTACTFIELD_PROPERTY_PREF] &&
+ !set_bool(record,
+ *metadata.ids[ECORDOVA_CONTACTFIELD_PROPERTY_PREF],
+ pd->pref))
+ return false;
+
+ return true;
+}
+
+char *
+ecordova_contactnumber_type2label(int type, const char *custom)
+{
+ switch (type)
+ {
+ case CONTACTS_NUMBER_TYPE_HOME:
+ return strdup("Home");
+ case CONTACTS_NUMBER_TYPE_WORK:
+ return strdup("Work");
+ case CONTACTS_NUMBER_TYPE_VOICE:
+ return strdup("Voice");
+ case CONTACTS_NUMBER_TYPE_FAX:
+ return strdup("Fax");
+ case CONTACTS_NUMBER_TYPE_MSG:
+ return strdup("Msg");
+ case CONTACTS_NUMBER_TYPE_CELL:
+ return strdup("Cell");
+ case CONTACTS_NUMBER_TYPE_PAGER:
+ return strdup("Pager");
+ case CONTACTS_NUMBER_TYPE_BBS:
+ return strdup("BBS");
+ case CONTACTS_NUMBER_TYPE_MODEM:
+ return strdup("Modem");
+ case CONTACTS_NUMBER_TYPE_CAR:
+ return strdup("Car");
+ case CONTACTS_NUMBER_TYPE_ISDN:
+ return strdup("ISDN");
+ case CONTACTS_NUMBER_TYPE_VIDEO:
+ return strdup("Video");
+ case CONTACTS_NUMBER_TYPE_PCS:
+ return strdup("Pcs");
+ case CONTACTS_NUMBER_TYPE_COMPANY_MAIN:
+ return strdup("Company_Main");
+ case CONTACTS_NUMBER_TYPE_RADIO:
+ return strdup("Radio");
+ case CONTACTS_NUMBER_TYPE_MAIN:
+ return strdup("Main");
+ case CONTACTS_NUMBER_TYPE_ASSISTANT:
+ return strdup("Assistant");
+ case CONTACTS_NUMBER_TYPE_OTHER:
+ case CONTACTS_NUMBER_TYPE_CUSTOM:
+ default:
+ if (custom)
+ return strdup(custom);
+ return NULL;
+ }
+}
+
+int
+ecordova_contactnumber_label2type(const char *label)
+{
+ if (!label)
+ return CONTACTS_NUMBER_TYPE_OTHER;
+ if (strcasecmp(label, "Home") == 0)
+ return CONTACTS_NUMBER_TYPE_HOME;
+ if (strcasecmp(label, "Work") == 0)
+ return CONTACTS_NUMBER_TYPE_WORK;
+ if (strcasecmp(label, "Voice") == 0)
+ return CONTACTS_NUMBER_TYPE_VOICE;
+ if (strcasecmp(label, "Fax") == 0)
+ return CONTACTS_NUMBER_TYPE_FAX;
+ if (strcasecmp(label, "Msg") == 0)
+ return CONTACTS_NUMBER_TYPE_MSG;
+ if (strcasecmp(label, "Cell") == 0)
+ return CONTACTS_NUMBER_TYPE_CELL;
+ if (strcasecmp(label, "Pager") == 0)
+ return CONTACTS_NUMBER_TYPE_PAGER;
+ if (strcasecmp(label, "BBS") == 0)
+ return CONTACTS_NUMBER_TYPE_BBS;
+ if (strcasecmp(label, "Modem") == 0)
+ return CONTACTS_NUMBER_TYPE_MODEM;
+ if (strcasecmp(label, "Car") == 0)
+ return CONTACTS_NUMBER_TYPE_CAR;
+ if (strcasecmp(label, "ISDN") == 0)
+ return CONTACTS_NUMBER_TYPE_ISDN;
+ if (strcasecmp(label, "Video") == 0)
+ return CONTACTS_NUMBER_TYPE_VIDEO;
+ if (strcasecmp(label, "Pcs") == 0)
+ return CONTACTS_NUMBER_TYPE_PCS;
+ if (strcasecmp(label, "Company_Main") == 0)
+ return CONTACTS_NUMBER_TYPE_COMPANY_MAIN;
+ if (strcasecmp(label, "Radio") == 0)
+ return CONTACTS_NUMBER_TYPE_RADIO;
+ if (strcasecmp(label, "Main") == 0)
+ return CONTACTS_NUMBER_TYPE_MAIN;
+ if (strcasecmp(label, "Assistant") == 0)
+ return CONTACTS_NUMBER_TYPE_ASSISTANT;
+
+ return CONTACTS_NUMBER_TYPE_CUSTOM;
+}
+
+char *
+ecordova_contactemail_type2label(int type, const char *custom)
+{
+ switch (type)
+ {
+ case CONTACTS_EMAIL_TYPE_HOME:
+ return strdup("Home");
+ case CONTACTS_EMAIL_TYPE_WORK:
+ return strdup("Work");
+ case CONTACTS_EMAIL_TYPE_MOBILE:
+ return strdup("Mobile");
+ case CONTACTS_EMAIL_TYPE_OTHER:
+ case CONTACTS_EMAIL_TYPE_CUSTOM:
+ default:
+ if (custom)
+ return strdup(custom);
+ return NULL;
+ }
+}
+
+int
+ecordova_contactemail_label2type(const char *label)
+{
+ if (!label)
+ return CONTACTS_EMAIL_TYPE_OTHER;
+ if (strcasecmp(label, "Home") == 0)
+ return CONTACTS_EMAIL_TYPE_HOME;
+ if (strcasecmp(label, "Work") == 0)
+ return CONTACTS_EMAIL_TYPE_WORK;
+ if (strcasecmp(label, "Mobile") == 0)
+ return CONTACTS_EMAIL_TYPE_MOBILE;
+
+ return CONTACTS_EMAIL_TYPE_CUSTOM;
+}
+
+char *
+ecordova_contactmessenger_type2label(int type, const char *custom)
+{
+ switch (type)
+ {
+ case CONTACTS_MESSENGER_TYPE_GOOGLE:
+ return strdup("Google");
+ case CONTACTS_MESSENGER_TYPE_WLM:
+ return strdup("Wlm");
+ case CONTACTS_MESSENGER_TYPE_YAHOO:
+ return strdup("Yahoo");
+ case CONTACTS_MESSENGER_TYPE_FACEBOOK:
+ return strdup("Facebook");
+ case CONTACTS_MESSENGER_TYPE_ICQ:
+ return strdup("Icq");
+ case CONTACTS_MESSENGER_TYPE_AIM:
+ return strdup("Aim");
+ case CONTACTS_MESSENGER_TYPE_QQ:
+ return strdup("Qq");
+ case CONTACTS_MESSENGER_TYPE_JABBER:
+ return strdup("Jabber");
+ case CONTACTS_MESSENGER_TYPE_SKYPE:
+ return strdup("Skype");
+ case CONTACTS_MESSENGER_TYPE_IRC:
+ return strdup("IRC");
+ case CONTACTS_MESSENGER_TYPE_OTHER:
+ case CONTACTS_MESSENGER_TYPE_CUSTOM:
+ default:
+ if (custom)
+ return strdup(custom);
+ return NULL;
+ }
+}
+
+int
+ecordova_contactmessenger_label2type(const char *label)
+{
+ if (!label)
+ return CONTACTS_MESSENGER_TYPE_OTHER;
+ if (strcasecmp(label, "Google") == 0)
+ return CONTACTS_MESSENGER_TYPE_GOOGLE;
+ if (strcasecmp(label, "Wlm") == 0)
+ return CONTACTS_MESSENGER_TYPE_WLM;
+ if (strcasecmp(label, "Yahoo") == 0)
+ return CONTACTS_MESSENGER_TYPE_YAHOO;
+ if (strcasecmp(label, "Facebook") == 0)
+ return CONTACTS_MESSENGER_TYPE_FACEBOOK;
+ if (strcasecmp(label, "Icq") == 0)
+ return CONTACTS_MESSENGER_TYPE_ICQ;
+ if (strcasecmp(label, "Aim") == 0)
+ return CONTACTS_MESSENGER_TYPE_AIM;
+ if (strcasecmp(label, "Qq") == 0)
+ return CONTACTS_MESSENGER_TYPE_QQ;
+ if (strcasecmp(label, "Jabber") == 0)
+ return CONTACTS_MESSENGER_TYPE_JABBER;
+ if (strcasecmp(label, "Skype") == 0)
+ return CONTACTS_MESSENGER_TYPE_SKYPE;
+ if (strcasecmp(label, "IRC") == 0)
+ return CONTACTS_MESSENGER_TYPE_IRC;
+
+ return CONTACTS_MESSENGER_TYPE_CUSTOM;
+}
+
+char *
+ecordova_contactimage_type2label(int type EINA_UNUSED, const char *custom)
+{
+ return custom ? strdup(custom) : NULL;
+}
+
+int
+ecordova_contactimage_label2type(const char *label EINA_UNUSED)
+{
+ return 0;
+}
+
+char *
+ecordova_contacturl_type2label(int type, const char *custom)
+{
+ switch (type)
+ {
+ case CONTACTS_URL_TYPE_HOME:
+ return strdup("Home");
+ case CONTACTS_URL_TYPE_WORK:
+ return strdup("Work");
+ case CONTACTS_URL_TYPE_OTHER:
+ case CONTACTS_URL_TYPE_CUSTOM:
+ default:
+ if (custom)
+ return strdup(custom);
+ return NULL;
+ }
+}
+
+int
+ecordova_contacturl_label2type(const char *label)
+{
+ if (!label)
+ return CONTACTS_URL_TYPE_OTHER;
+ if (strcasecmp(label, "Home") == 0)
+ return CONTACTS_URL_TYPE_HOME;
+ if (strcasecmp(label, "Work") == 0)
+ return CONTACTS_URL_TYPE_WORK;
+ return CONTACTS_URL_TYPE_CUSTOM;
+}
+
+#include "ecordova_contactfield.eo.c"
diff --git a/src/lib/ecordova/ecordova_contactfield.eo b/src/lib/ecordova/ecordova_contactfield.eo
new file mode 100644
index 0000000000..b61930547f
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contactfield.eo
@@ -0,0 +1,57 @@
+class Ecordova.ContactField (Eo.Base) {
+ [[Contains information about a single contact.]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_ContactField constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ params {
+ type: const(char)*;
+ [[A string that indicates what type of field this is, home for
+ example.
+ ]]
+
+ value: const(char)*;
+ [[The value of the field, such as a phone number or email
+ address.
+ ]]
+
+ pref: bool;
+ [[Set to true if this ContactField contains the user's preferred
+ value.
+ ]]
+ }
+ }
+ @property id {
+ get {}
+ values {
+ id: int;
+ }
+ }
+ @property type {
+ values {
+ type: const(char)*;
+ }
+ }
+ @property value {
+ values {
+ value: const(char)*;
+ }
+ }
+ @property pref {
+ values {
+ preferred: bool;
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_contactfield_private.h b/src/lib/ecordova/ecordova_contactfield_private.h
new file mode 100644
index 0000000000..408a40addc
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contactfield_private.h
@@ -0,0 +1,58 @@
+#ifndef _ECORDOVA_CONTACTFIELD_PRIVATE_H
+#define _ECORDOVA_CONTACTFIELD_PRIVATE_H
+
+#include "ecordova_private.h"
+#include "ecordova_contactfield.eo.h"
+
+#include <contacts.h>
+#include <stdbool.h>
+
+typedef enum _Ecordova_ContactField_Property
+{
+ ECORDOVA_CONTACTFIELD_PARENT_PROPERTY_ID,
+ ECORDOVA_CONTACTFIELD_PROPERTY_ID,
+ ECORDOVA_CONTACTFIELD_PROPERTY_TYPE,
+ ECORDOVA_CONTACTFIELD_PROPERTY_LABEL,
+ ECORDOVA_CONTACTFIELD_PROPERTY_VALUE,
+ ECORDOVA_CONTACTFIELD_PROPERTY_PREF,
+ ECORDOVA_CONTACTFIELD_PROPERTY_COUNT
+} Ecordova_ContactField_Property;
+
+typedef struct _Ecordova_ContactField_Metadata
+{
+ const char * const *uri;
+ const unsigned int *ids[ECORDOVA_CONTACTFIELD_PROPERTY_COUNT];
+ char *(*type2label)(int type, const char *custom);
+ int(*label2type)(const char *label);
+} Ecordova_ContactField_Metadata;
+
+typedef struct _Ecordova_ContactField_Data Ecordova_ContactField_Data;
+
+/**
+ * Ecordova.ContactField private data
+ */
+struct _Ecordova_ContactField_Data
+{
+ Eo *obj;
+ int id;
+ char *type;
+ char *value;
+ Eina_Bool pref;
+ Ecordova_ContactField_Metadata metadata;
+};
+
+bool ecordova_contactfield_import(Ecordova_ContactField *, contacts_record_h, const Ecordova_ContactField_Metadata);
+bool ecordova_contactfield_export(Ecordova_ContactField *, contacts_record_h, const Ecordova_ContactField_Metadata);
+
+char *ecordova_contactnumber_type2label(int, const char *);
+int ecordova_contactnumber_label2type(const char *);
+char *ecordova_contactemail_type2label(int, const char *);
+int ecordova_contactemail_label2type(const char *);
+char *ecordova_contactmessenger_type2label(int, const char *);
+int ecordova_contactmessenger_label2type(const char *);
+char *ecordova_contactimage_type2label(int, const char *);
+int ecordova_contactimage_label2type(const char *);
+char *ecordova_contacturl_type2label(int, const char *);
+int ecordova_contacturl_label2type(const char *);
+
+#endif
diff --git a/src/lib/ecordova/ecordova_contactname.c b/src/lib/ecordova/ecordova_contactname.c
new file mode 100644
index 0000000000..87cdcbfaaf
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contactname.c
@@ -0,0 +1,257 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_contactname_private.h"
+#include "ecordova_contact_private.h"
+#include "ecordova_contacts_record_utils.h"
+#include "ecordova_contactname.eo.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define MY_CLASS ECORDOVA_CONTACTNAME_CLASS
+#define MY_CLASS_NAME "Ecordova_ContactName"
+
+static Eo_Base *
+_ecordova_contactname_eo_base_constructor(Eo *obj,
+ Ecordova_ContactName_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->record = NULL;
+ int ret = contacts_record_create(_contacts_name._uri, &pd->record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, NULL);
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_contactname_constructor(Eo *obj,
+ Ecordova_ContactName_Data *pd EINA_UNUSED,
+ const char *formatted,
+ const char *family_name,
+ const char *given_name,
+ const char *middle,
+ const char *prefix,
+ const char *suffix)
+{
+ DBG("(%p)", obj);
+ eo_do(obj,
+ ecordova_contactname_formatted_set(formatted),
+ ecordova_contactname_family_name_set(family_name),
+ ecordova_contactname_given_name_set(given_name),
+ ecordova_contactname_middle_set(middle),
+ ecordova_contactname_prefix_set(prefix),
+ ecordova_contactname_suffix_set(suffix));
+}
+
+static void
+_ecordova_contactname_eo_base_destructor(Eo *obj, Ecordova_ContactName_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ int ret = contacts_record_destroy(pd->record, true);
+ EINA_SAFETY_ON_FALSE_RETURN(CONTACTS_ERROR_NONE == ret);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static const char *
+_ecordova_contactname_formatted_get(Eo *obj,
+ Ecordova_ContactName_Data *pd EINA_UNUSED)
+{
+ Eo *parent = NULL;
+ eo_do(obj, parent = eo_parent_get());
+ EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
+
+ Ecordova_Contact_Data *parent_pd = eo_data_scope_get(parent, ECORDOVA_CONTACT_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(parent_pd, NULL);
+
+ const char *value = NULL;
+ get_str_p(parent_pd->record, _contacts_contact.display_name, &value);
+ return value;
+}
+
+static void
+_ecordova_contactname_formatted_set(Eo *obj,
+ Ecordova_ContactName_Data *pd EINA_UNUSED,
+ const char *value)
+{
+ Eo *parent = NULL;
+ eo_do(obj, parent = eo_parent_get());
+ EINA_SAFETY_ON_NULL_RETURN(parent);
+
+ Ecordova_Contact_Data *parent_pd = eo_data_scope_get(parent, ECORDOVA_CONTACT_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN(parent_pd);
+
+ set_str(parent_pd->record, _contacts_contact.display_name, value);
+}
+
+static const char *
+_ecordova_contactname_family_name_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactName_Data *pd)
+{
+ const char *value = NULL;
+ get_str_p(pd->record, _contacts_name.last, &value);
+ return value;
+}
+
+static void
+_ecordova_contactname_family_name_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactName_Data *pd,
+ const char *value)
+{
+ set_str(pd->record, _contacts_name.last, value);
+}
+
+static const char *
+_ecordova_contactname_given_name_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactName_Data *pd)
+{
+ const char *value = NULL;
+ get_str_p(pd->record, _contacts_name.first, &value);
+ return value;
+}
+
+static void
+_ecordova_contactname_given_name_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactName_Data *pd,
+ const char *value)
+{
+ set_str(pd->record, _contacts_name.first, value);
+}
+
+static const char *
+_ecordova_contactname_middle_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactName_Data *pd)
+{
+ const char *value = NULL;
+ get_str_p(pd->record, _contacts_name.addition, &value);
+ return value;
+}
+
+static void
+_ecordova_contactname_middle_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactName_Data *pd,
+ const char *value)
+{
+ set_str(pd->record, _contacts_name.addition, value);
+}
+
+static const char *
+_ecordova_contactname_prefix_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactName_Data *pd)
+{
+ const char *value = NULL;
+ get_str_p(pd->record, _contacts_name.prefix, &value);
+ return value;
+}
+
+static void
+_ecordova_contactname_prefix_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactName_Data *pd,
+ const char *value)
+{
+ set_str(pd->record, _contacts_name.prefix, value);
+}
+
+static const char *
+_ecordova_contactname_suffix_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactName_Data *pd)
+{
+ const char *value = NULL;
+ get_str_p(pd->record, _contacts_name.suffix, &value);
+ return value;
+}
+
+static void
+_ecordova_contactname_suffix_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactName_Data *pd,
+ const char *value)
+{
+ set_str(pd->record, _contacts_name.suffix, value);
+}
+
+bool
+ecordova_contactname_import(Ecordova_ContactName *obj,
+ contacts_record_h contacts_record)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(obj, false);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(contacts_record, false);
+
+ Ecordova_ContactName_Data *pd = eo_data_scope_get(obj, ECORDOVA_CONTACTNAME_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pd, false);
+
+ int ret;
+
+ int count = 0;
+ ret = contacts_record_get_child_record_count(contacts_record,
+ _contacts_contact.name,
+ &count);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(count == 1, false);
+
+ contacts_record_h contactname_record = NULL;
+ ret = contacts_record_get_child_record_at_p(contacts_record,
+ _contacts_contact.name,
+ 0,
+ &contactname_record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ ret = contacts_record_destroy(pd->record, true);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+ ret = contacts_record_clone(contactname_record, &pd->record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ // TODO: check display name
+
+ return true;
+}
+
+bool
+ecordova_contactname_export(Ecordova_ContactName *obj,
+ contacts_record_h contacts_record)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(obj, false);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(contacts_record, false);
+
+ Ecordova_ContactName_Data *pd = eo_data_scope_get(obj, ECORDOVA_CONTACTNAME_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pd, false);
+
+ contacts_record_h contactname_record = NULL;
+ int ret = contacts_record_clone(pd->record, &contactname_record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ ret = contacts_record_add_child_record(contacts_record,
+ _contacts_contact.name,
+ contactname_record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ // TODO: check display name
+
+ return true;
+}
+
+Ecordova_ContactName *
+ecordova_contactname_clone(Ecordova_ContactName *other)
+{
+ Ecordova_ContactName *cloned = eo_add(ECORDOVA_CONTACTNAME_CLASS, NULL);
+
+ Ecordova_ContactName_Data *cloned_pd = eo_data_scope_get(cloned, ECORDOVA_CONTACTNAME_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(cloned_pd, NULL);
+ Ecordova_ContactName_Data *other_pd = eo_data_scope_get(other, ECORDOVA_CONTACTNAME_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(other_pd, NULL);
+
+ int ret = contacts_record_destroy(cloned_pd->record, true);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, NULL);
+ ret = contacts_record_clone(other_pd->record, &cloned_pd->record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, NULL);
+
+ return cloned;
+}
+
+
+#include "ecordova_contactname.eo.c"
diff --git a/src/lib/ecordova/ecordova_contactname.eo b/src/lib/ecordova/ecordova_contactname.eo
new file mode 100644
index 0000000000..435d714dbb
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contactname.eo
@@ -0,0 +1,58 @@
+class Ecordova.ContactName (Eo.Base) {
+ [[Contact name.]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_ContactName constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ params {
+ formatted: const(char)*; [[The complete name of the contact.]]
+ family_name: const(char)*; [[The contact's family name.]]
+ given_name: const(char)*; [[The contact's given name.]]
+ middle: const(char)*; [[The contact's middle name.]]
+ prefix: const(char)*; [[The contact's prefix (example Mr. or Dr.)]]
+ suffix: const(char)*; [[The contact's suffix (example Esq.).]]
+ }
+ }
+ @property formatted {
+ values {
+ formatted: const(char)*;
+ }
+ }
+ @property family_name {
+ values {
+ family_name: const(char)*;
+ }
+ }
+ @property given_name {
+ values {
+ given_name: const(char)*;
+ }
+ }
+ @property middle {
+ values {
+ middle: const(char)*;
+ }
+ }
+ @property prefix {
+ values {
+ prefix: const(char)*;
+ }
+ }
+ @property suffix {
+ values {
+ suffix: const(char)*;
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_contactname_private.h b/src/lib/ecordova/ecordova_contactname_private.h
new file mode 100644
index 0000000000..ccdcd61cb8
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contactname_private.h
@@ -0,0 +1,25 @@
+#ifndef _ECORDOVA_CONTACTNAME_PRIVATE_H
+#define _ECORDOVA_CONTACTNAME_PRIVATE_H
+
+#include "ecordova_private.h"
+#include "ecordova_contactname.eo.h"
+
+#include <contacts.h>
+#include <stdbool.h>
+
+typedef struct _Ecordova_ContactName_Data Ecordova_ContactName_Data;
+
+/**
+ * Ecordova.ContactName private data
+ */
+struct _Ecordova_ContactName_Data
+{
+ Eo *obj;
+ contacts_record_h record;
+};
+
+bool ecordova_contactname_import(Ecordova_ContactName *, contacts_record_h);
+bool ecordova_contactname_export(Ecordova_ContactName *, contacts_record_h);
+Ecordova_ContactName *ecordova_contactname_clone(Ecordova_ContactName *);
+
+#endif
diff --git a/src/lib/ecordova/ecordova_contactorganization.c b/src/lib/ecordova/ecordova_contactorganization.c
new file mode 100644
index 0000000000..50cbde09cf
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contactorganization.c
@@ -0,0 +1,232 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_contactorganization_private.h"
+#include "ecordova_contacts_record_utils.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define MY_CLASS ECORDOVA_CONTACTORGANIZATION_CLASS
+#define MY_CLASS_NAME "Ecordova_ContactOrganization"
+
+static Eo_Base *
+_ecordova_contactorganization_eo_base_constructor(Eo *obj,
+ Ecordova_ContactOrganization_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->id = 0;
+ pd->record = NULL;
+ int ret = contacts_record_create(_contacts_company._uri, &pd->record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, NULL);
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_contactorganization_constructor(Eo *obj,
+ Ecordova_ContactOrganization_Data *pd EINA_UNUSED,
+ Eina_Bool pref EINA_UNUSED,
+ const char *type,
+ const char *name,
+ const char *dept,
+ const char *title)
+{
+ DBG("(%p)", obj);
+ eo_do(obj,
+ ecordova_contactorganization_type_set(type),
+ ecordova_contactorganization_name_set(name),
+ ecordova_contactorganization_dept_set(dept),
+ ecordova_contactorganization_title_set(title));
+}
+
+static void
+_ecordova_contactorganization_eo_base_destructor(Eo *obj,
+ Ecordova_ContactOrganization_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ int ret = contacts_record_destroy(pd->record, true);
+ EINA_SAFETY_ON_FALSE_RETURN(CONTACTS_ERROR_NONE == ret);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static int
+_ecordova_contactorganization_id_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactOrganization_Data *pd)
+{
+ return pd->id;
+}
+
+static Eina_Bool
+_ecordova_contactorganization_pref_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactOrganization_Data *pd EINA_UNUSED)
+{
+ ERR("%s", "Not implemented");
+ return EINA_FALSE;
+}
+
+static void
+_ecordova_contactorganization_pref_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactOrganization_Data *pd EINA_UNUSED,
+ Eina_Bool pref EINA_UNUSED)
+{
+ ERR("%s", "Not implemented");
+}
+
+static const char *
+_ecordova_contactorganization_type_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactOrganization_Data *pd)
+{
+ int type;
+ if (!get_int(pd->record, _contacts_company.type, &type))
+ return NULL;
+
+ switch (type)
+ {
+ case CONTACTS_COMPANY_TYPE_WORK:
+ return "Work";
+ case CONTACTS_COMPANY_TYPE_OTHER:
+ case CONTACTS_COMPANY_TYPE_CUSTOM:
+ default:
+ {
+ const char *custom = NULL;
+ get_str_p(pd->record, _contacts_company.label, &custom);
+ return custom;
+ }
+ }
+}
+
+static void
+_ecordova_contactorganization_type_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactOrganization_Data *pd,
+ const char *value)
+{
+ int type = CONTACTS_COMPANY_TYPE_OTHER;
+ if (!value || strlen(value) == 0)
+ type = CONTACTS_COMPANY_TYPE_OTHER;
+ else if (strcasecmp(value, "Work"))
+ type = CONTACTS_COMPANY_TYPE_WORK;
+ else
+ type = CONTACTS_COMPANY_TYPE_CUSTOM;
+
+ set_int(pd->record, _contacts_company.type, type);
+ if (strlen(value) != 0)
+ set_str(pd->record, _contacts_company.label, value);
+}
+
+static const char *
+_ecordova_contactorganization_name_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactOrganization_Data *pd)
+{
+ const char *value = NULL;
+ get_str_p(pd->record, _contacts_company.name, &value);
+ return value;
+}
+
+static void
+_ecordova_contactorganization_name_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactOrganization_Data *pd,
+ const char *value)
+{
+ set_str(pd->record, _contacts_company.name, value);
+}
+
+static const char *
+_ecordova_contactorganization_dept_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactOrganization_Data *pd)
+{
+ const char *value = NULL;
+ get_str_p(pd->record, _contacts_company.department, &value);
+ return value;
+}
+
+static void
+_ecordova_contactorganization_dept_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactOrganization_Data *pd,
+ const char *value)
+{
+ set_str(pd->record, _contacts_company.department, value);
+}
+
+static const char *
+_ecordova_contactorganization_title_get(Eo *obj EINA_UNUSED,
+ Ecordova_ContactOrganization_Data *pd)
+{
+ const char *value = NULL;
+ get_str_p(pd->record, _contacts_company.job_title, &value);
+ return value;
+}
+
+static void
+_ecordova_contactorganization_title_set(Eo *obj EINA_UNUSED,
+ Ecordova_ContactOrganization_Data *pd,
+ const char *value)
+{
+ set_str(pd->record, _contacts_company.job_title, value);
+}
+
+bool
+ecordova_contactorganization_import(Ecordova_ContactOrganization *obj,
+ contacts_record_h child_record)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(obj, false);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(child_record, false);
+
+ Ecordova_ContactOrganization_Data *pd = eo_data_scope_get(obj, ECORDOVA_CONTACTORGANIZATION_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pd, false);
+
+ int ret = contacts_record_destroy(pd->record, true);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+ ret = contacts_record_clone(child_record, &pd->record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ return get_int(child_record, _contacts_company.id, &pd->id);
+}
+
+bool
+ecordova_contactorganization_export(Ecordova_ContactOrganization *obj,
+ contacts_record_h contacts_record)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(obj, false);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(contacts_record, false);
+
+ Ecordova_ContactOrganization_Data *pd = eo_data_scope_get(obj, ECORDOVA_CONTACTORGANIZATION_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pd, false);
+
+ contacts_record_h child_record = NULL;
+ int ret = contacts_record_clone(pd->record, &child_record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ ret = contacts_record_add_child_record(contacts_record,
+ _contacts_contact.company,
+ child_record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ return true;
+}
+
+Ecordova_ContactOrganization *
+ecordova_contactorganization_clone(Ecordova_ContactOrganization *other)
+{
+ Ecordova_ContactOrganization *cloned = eo_add(ECORDOVA_CONTACTORGANIZATION_CLASS, NULL);
+
+ Ecordova_ContactOrganization_Data *cloned_pd = eo_data_scope_get(cloned, ECORDOVA_CONTACTORGANIZATION_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(cloned_pd, NULL);
+ Ecordova_ContactOrganization_Data *other_pd = eo_data_scope_get(other, ECORDOVA_CONTACTORGANIZATION_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(other_pd, NULL);
+
+ int ret = contacts_record_destroy(cloned_pd->record, true);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, NULL);
+ ret = contacts_record_clone(other_pd->record, &cloned_pd->record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, NULL);
+
+ return cloned;
+}
+
+#include "ecordova_contactorganization.eo.c"
diff --git a/src/lib/ecordova/ecordova_contactorganization.eo b/src/lib/ecordova/ecordova_contactorganization.eo
new file mode 100644
index 0000000000..baf6b275cd
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contactorganization.eo
@@ -0,0 +1,72 @@
+class Ecordova.ContactOrganization (Eo.Base) {
+ [[Contact name.]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_ContactOrganization constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ params {
+ pref: bool;
+ [[Set to true if this ContactOrganization contains the user's
+ preferred value.
+ ]]
+
+ type: const(char)*;
+ [[A string that indicates what type of field this is, home for
+ example.
+ ]]
+
+ name: const(char)*;
+ [[The name of the organization.]]
+
+ dept: const(char)*;
+ [[The department the contract works for.]]
+
+ title: const(char)*;
+ [[The contact's title at the organization.]]
+
+ }
+ }
+ @property id {
+ get {}
+ values {
+ id: int;
+ }
+ }
+ @property pref {
+ values {
+ pref: bool;
+ }
+ }
+ @property type {
+ values {
+ type: const(char)*;
+ }
+ }
+ @property name {
+ values {
+ name: const(char)*;
+ }
+ }
+ @property dept {
+ values {
+ dept: const(char)*;
+ }
+ }
+ @property title {
+ values {
+ title: const(char)*;
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_contactorganization_private.h b/src/lib/ecordova/ecordova_contactorganization_private.h
new file mode 100644
index 0000000000..643b11792d
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contactorganization_private.h
@@ -0,0 +1,25 @@
+#ifndef _ECORDOVA_CONTACTORGANIZATION_PRIVATE_H
+#define _ECORDOVA_CONTACTORGANIZATION_PRIVATE_H
+
+#include "ecordova_private.h"
+#include "ecordova_contactorganization.eo.h"
+
+#include <contacts.h>
+
+typedef struct _Ecordova_ContactOrganization_Data Ecordova_ContactOrganization_Data;
+
+/**
+ * Ecordova.ContactOrganization private data
+ */
+struct _Ecordova_ContactOrganization_Data
+{
+ Eo *obj;
+ int id;
+ contacts_record_h record;
+};
+
+bool ecordova_contactorganization_import(Ecordova_ContactOrganization *, contacts_record_h);
+bool ecordova_contactorganization_export(Ecordova_ContactOrganization *, contacts_record_h);
+Ecordova_ContactOrganization *ecordova_contactorganization_clone(Ecordova_ContactOrganization *);
+
+#endif
diff --git a/src/lib/ecordova/ecordova_contacts.c b/src/lib/ecordova/ecordova_contacts.c
new file mode 100644
index 0000000000..c914ec08fb
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contacts.c
@@ -0,0 +1,519 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_contacts_private.h"
+#include "ecordova_contact_private.h"
+#include "ecordova_contacts_record_utils.h"
+
+#include <contacts.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define MY_CLASS ECORDOVA_CONTACTS_CLASS
+#define MY_CLASS_NAME "Ecordova_Contacts"
+
+typedef enum Contacts_Search_Id {
+ SEARCH_CONTACT,
+ SEARCH_ADDRESS,
+ SEARCH_EVENT,
+ SEARCH_COMPANY,
+ SEARCH_EMAIL,
+ SEARCH_NAME,
+ SEARCH_NICKNAME,
+ SEARCH_MESSENGER,
+ SEARCH_NOTE,
+ SEARCH_NUMBER,
+ SEARCH_URL,
+ SEARCH_IMAGE,
+ SEARCH_ID_COUNT
+} Contacts_Search_Id;
+
+static contacts_filter_h _filter_get(contacts_filter_h *, const char *);
+static contacts_list_h _get_records(const Eina_List *, const Ecordova_Contacts_FindOptions *);
+static bool _search_records(contacts_filter_h, const char *, contacts_list_h *, Eina_Bool);
+static bool _populate_list(contacts_list_h, Eina_Hash *, contacts_filter_h, const char *, int, Eina_Bool);
+
+static Eo_Base *
+_ecordova_contacts_eo_base_constructor(Eo *obj, Ecordova_Contacts_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_contacts_constructor(Eo *obj EINA_UNUSED,
+ Ecordova_Contacts_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+}
+
+static void
+_ecordova_contacts_eo_base_destructor(Eo *obj,
+ Ecordova_Contacts_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_contacts_find(Eo *obj,
+ Ecordova_Contacts_Data *pd EINA_UNUSED,
+ const Eina_List *fields,
+ const Ecordova_Contacts_FindOptions *options)
+{
+ DBG("(%p)", obj);
+ if (!fields)
+ {
+ Ecordova_Contacts_Error error = ECORDOVA_CONTACTS_ERROR_INVALID_ARGUMENT_ERROR;
+ eo_do(obj, eo_event_callback_call(ECORDOVA_CONTACTS_EVENT_ERROR, &error));
+ return;
+ }
+
+ // TODO: load all records in a background thread
+
+ contacts_list_h list = NULL;
+
+ const char *field = eina_list_data_get(fields);
+ if (strcmp("*", field) == 0)
+ {
+ int ret = contacts_db_get_all_records(_contacts_contact._uri, 0, 0, &list);
+ if (CONTACTS_ERROR_NONE != ret)
+ {
+ ERR("%s returned %d", "contacts_db_get_all_records", ret);
+ Ecordova_Contacts_Error error = ECORDOVA_CONTACTS_ERROR_UNKNOWN_ERROR;
+ eo_do(obj, eo_event_callback_call(ECORDOVA_CONTACTS_EVENT_ERROR, &error));
+ return;
+ }
+ }
+ else
+ {
+ if (!options)
+ {
+ ERR("%s", "options cannot be NULL");
+ Ecordova_Contacts_Error error = ECORDOVA_CONTACTS_ERROR_INVALID_ARGUMENT_ERROR;
+ eo_do(obj, eo_event_callback_call(ECORDOVA_CONTACTS_EVENT_ERROR, &error));
+ return;
+ }
+
+ if (!options->filter)
+ {
+ ERR("%s", "options.filter cannot be NULL");
+ Ecordova_Contacts_Error error = ECORDOVA_CONTACTS_ERROR_INVALID_ARGUMENT_ERROR;
+ eo_do(obj, eo_event_callback_call(ECORDOVA_CONTACTS_EVENT_ERROR, &error));
+ return;
+ }
+
+ list = _get_records(fields, options);
+ if (!list)
+ {
+ Ecordova_Contacts_Error error = ECORDOVA_CONTACTS_ERROR_INVALID_ARGUMENT_ERROR;
+ eo_do(obj, eo_event_callback_call(ECORDOVA_CONTACTS_EVENT_ERROR, &error));
+ return;
+ }
+ }
+
+ Eina_Array *contacts = eina_array_new(1);
+ do
+ {
+ contacts_record_h record = NULL;
+ int ret = contacts_list_get_current_record_p(list, &record);
+ if (CONTACTS_ERROR_NONE != ret || !record)
+ {
+ WRN("contacts_list_get_current_record_p returned %d", ret);
+ break;
+ }
+
+ Ecordova_Contact *contact = eo_add(ECORDOVA_CONTACT_CLASS, NULL);
+ if (!ecordova_contact_import(contact, record))
+ {
+ WRN("%s", "Error importing contact record");
+ eo_unref(contact);
+ continue;
+ }
+
+ eina_array_push(contacts, contact);
+
+ } while (contacts_list_next(list) == CONTACTS_ERROR_NONE);
+
+ eo_do(obj, eo_event_callback_call(ECORDOVA_CONTACTS_EVENT_FIND_SUCCESS, contacts));
+
+ int ret;
+ size_t i;
+ Ecordova_Contact *contact;
+ Eina_Array_Iterator it;
+
+ EINA_ARRAY_ITER_NEXT(contacts, i, contact, it)
+ eo_unref(contact);
+ eina_array_free(contacts);
+
+ ret = contacts_list_destroy(list, true);
+ EINA_SAFETY_ON_FALSE_RETURN(CONTACTS_ERROR_NONE == ret);
+}
+
+static void
+_ecordova_contacts_contact_pick(Eo *obj EINA_UNUSED,
+ Ecordova_Contacts_Data *pd EINA_UNUSED)
+{
+ // TODO: pick_contact UI
+}
+
+static Ecordova_Contact *
+_ecordova_contacts_create(Eo *obj EINA_UNUSED,
+ Ecordova_Contacts_Data *pd EINA_UNUSED,
+ Ecordova_Contact *other EINA_UNUSED)
+{
+ // TODO: clone 'other' if it's not NULL
+ return eo_add(ECORDOVA_CONTACT_CLASS, NULL);
+}
+
+static contacts_filter_h
+_filter_get(contacts_filter_h *filter, const char *uri)
+{
+ if (NULL == *filter)
+ {
+ int ret = contacts_filter_create(uri, filter);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, NULL);
+ }
+ else
+ {
+ int ret = contacts_filter_add_operator(*filter, CONTACTS_FILTER_OPERATOR_OR);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, NULL);
+ }
+
+ return *filter;
+}
+
+static contacts_list_h
+_get_records(const Eina_List *fields,
+ const Ecordova_Contacts_FindOptions *options)
+{
+ contacts_list_h list = NULL;
+
+ typedef struct
+ {
+ const char *field;
+ unsigned int property_id;
+ enum {INT_FIELD, STRING_FIELD, BIRTHDAY_FIELD, ADDRESSES_FIELD} type;
+ Contacts_Search_Id search_id;
+ } Search_Metadata;
+
+ Search_Metadata search_metadata[] = {
+ {"id", _contacts_contact.id, INT_FIELD, SEARCH_CONTACT},
+ {"display_name", _contacts_contact.display_name, STRING_FIELD, SEARCH_CONTACT},
+ {"formatted", _contacts_contact.display_name, STRING_FIELD, SEARCH_CONTACT},
+ {"name", _contacts_contact.display_name, STRING_FIELD, SEARCH_CONTACT},
+ {"given_name", _contacts_name.first, STRING_FIELD, SEARCH_NAME},
+ {"family_name", _contacts_name.last, STRING_FIELD, SEARCH_NAME},
+ {"honorific_prefix", _contacts_name.prefix, STRING_FIELD, SEARCH_NAME},
+ {"honorific_suffix", _contacts_name.suffix, STRING_FIELD, SEARCH_NAME},
+ {"middle_name", _contacts_name.addition, STRING_FIELD, SEARCH_NAME},
+ {"country", _contacts_address.country, STRING_FIELD, SEARCH_ADDRESS},
+ {"locality", _contacts_address.locality, STRING_FIELD, SEARCH_ADDRESS},
+ {"postal_code", _contacts_address.postal_code, STRING_FIELD, SEARCH_ADDRESS},
+ {"region", _contacts_address.region, STRING_FIELD, SEARCH_ADDRESS},
+ {"street_address", _contacts_address.street, STRING_FIELD, SEARCH_ADDRESS},
+ {"phone_numbers", _contacts_number.number, STRING_FIELD, SEARCH_NUMBER},
+ {"emails", _contacts_email.email, STRING_FIELD, SEARCH_EMAIL},
+ {"urls", _contacts_url.url, STRING_FIELD, SEARCH_URL},
+ {"note", _contacts_note.note, STRING_FIELD, SEARCH_NOTE},
+ {"ims", _contacts_messenger.im_id, STRING_FIELD, SEARCH_MESSENGER},
+ {"nickname", _contacts_nickname.name, STRING_FIELD, SEARCH_NICKNAME},
+ {"department", _contacts_company.department, STRING_FIELD, SEARCH_COMPANY},
+ {"organizations", _contacts_company.name, STRING_FIELD, SEARCH_COMPANY},
+ {"title", _contacts_company.job_title, STRING_FIELD, SEARCH_COMPANY},
+ {"photos", _contacts_image.path, STRING_FIELD, SEARCH_IMAGE},
+ {"birthday", _contacts_event.date, BIRTHDAY_FIELD, SEARCH_EVENT},
+ {"addresses", 0, ADDRESSES_FIELD, SEARCH_ADDRESS},
+ // TODO: categories: "categories", ?
+ {0}
+ };
+
+ const char *uri[SEARCH_ID_COUNT] = {
+ [SEARCH_CONTACT] = _contacts_contact._uri,
+ [SEARCH_ADDRESS] = _contacts_address._uri,
+ [SEARCH_EVENT] = _contacts_event._uri,
+ [SEARCH_COMPANY] = _contacts_company._uri,
+ [SEARCH_EMAIL] = _contacts_email._uri,
+ [SEARCH_NAME] = _contacts_name._uri,
+ [SEARCH_NICKNAME] = _contacts_nickname._uri,
+ [SEARCH_MESSENGER] = _contacts_messenger._uri,
+ [SEARCH_NOTE] = _contacts_note._uri,
+ [SEARCH_NUMBER] = _contacts_number._uri,
+ [SEARCH_URL] = _contacts_url._uri,
+ [SEARCH_IMAGE] = _contacts_image._uri
+ };
+
+ contacts_filter_h filters[SEARCH_ID_COUNT] = {NULL};
+ int ret;
+ Eina_List *it;
+ const char *field;
+ EINA_LIST_FOREACH((Eina_List*)fields, it, field)
+ {
+ contacts_filter_h filter = NULL;
+
+ int i = 0;
+ Search_Metadata *metadata = NULL;
+ while ((metadata = &search_metadata[i++]) && metadata->field)
+ {
+ if (strcmp(metadata->field, field) != 0)
+ continue;
+
+ switch (metadata->type)
+ {
+ case INT_FIELD:
+ {
+ int value = 0;
+ if ((sscanf(options->filter, "%d", &value) != 1) &&
+ (sscanf(options->filter, "%x", &value) != 1) &&
+ (sscanf(options->filter, "%o", &value) != 1))
+ {
+ ERR("Cannot convert options.filter to int to match the contact %s", field);
+ goto on_error_1;
+ }
+
+ filter = _filter_get(&filters[metadata->search_id], uri[metadata->search_id]);
+ if (!filter) goto on_error_1;
+
+ ret = contacts_filter_add_int(filter, metadata->property_id, CONTACTS_MATCH_EQUAL, value);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_1);
+ break;
+ }
+ case STRING_FIELD:
+ {
+ filter = _filter_get(&filters[metadata->search_id], uri[metadata->search_id]);
+ if (!filter) goto on_error_1;
+
+ ret = contacts_filter_add_str(filter, metadata->property_id, CONTACTS_MATCH_CONTAINS, options->filter);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_1);
+ break;
+ }
+ case BIRTHDAY_FIELD:
+ {
+ int value = 0;
+
+ // TODO: Convert options->filter as date string to int
+
+ filter = _filter_get(&filters[metadata->search_id], uri[metadata->search_id]);
+ if (!filter) goto on_error_1;
+
+ ret = contacts_filter_add_int(filter, metadata->property_id, CONTACTS_MATCH_EQUAL, value);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_1);
+
+ int ret = contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_AND);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_1);
+
+ ret = contacts_filter_add_int(filter, _contacts_event.type, CONTACTS_MATCH_EQUAL, CONTACTS_EVENT_TYPE_BIRTH);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_1);
+
+ break;
+ }
+ case ADDRESSES_FIELD:
+ {
+ filter = _filter_get(&filters[metadata->search_id], uri[metadata->search_id]);
+ if (!filter) goto on_error_1;
+
+ ret = contacts_filter_add_str(filter, _contacts_address.country, CONTACTS_MATCH_CONTAINS, options->filter);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_1);
+
+ ret = contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_1);
+
+ ret = contacts_filter_add_str(filter, _contacts_address.region, CONTACTS_MATCH_CONTAINS, options->filter);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_1);
+
+ ret = contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_1);
+
+ ret = contacts_filter_add_str(filter, _contacts_address.locality, CONTACTS_MATCH_CONTAINS, options->filter);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_1);
+
+ ret = contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_1);
+
+ ret = contacts_filter_add_str(filter, _contacts_address.street, CONTACTS_MATCH_CONTAINS, options->filter);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_1);
+
+ ret = contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_1);
+
+ ret = contacts_filter_add_str(filter, _contacts_address.postal_code, CONTACTS_MATCH_CONTAINS, options->filter);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_1);
+
+ break;
+ }
+ }
+ }
+ }
+
+ Eina_Hash *contact_ids = eina_hash_int32_new(NULL);
+
+ if (filters[SEARCH_CONTACT])
+ {
+ if (!_search_records(filters[SEARCH_CONTACT], uri[SEARCH_CONTACT], &list, options->multiple))
+ goto on_error_2;
+
+ do
+ {
+ contacts_record_h record = NULL;
+ ret = contacts_list_get_current_record_p(list, &record);
+ if (CONTACTS_ERROR_NONE != ret || !record)
+ {
+ WRN("contacts_list_get_current_record_p returned %d", ret);
+ break;
+ }
+
+ int id;
+ bool ok = get_int(record, _contacts_contact.id, &id);
+ EINA_SAFETY_ON_FALSE_GOTO(ok, on_error_2);
+
+ ok = eina_hash_add(contact_ids, &id, &id) == EINA_TRUE;
+ EINA_SAFETY_ON_FALSE_GOTO(ok, on_error_2);
+
+ } while (contacts_list_next(list) == CONTACTS_ERROR_NONE);
+
+ contacts_list_first(list);
+ }
+ else
+ {
+ ret = contacts_list_create(&list);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_2);
+ }
+
+
+ for (int search_id = 0; search_id < SEARCH_ID_COUNT; ++search_id)
+ {
+ if (SEARCH_CONTACT == search_id || !filters[search_id])
+ continue;
+
+ if (!options->multiple)
+ {
+ int count = 0;
+ ret = contacts_list_get_count(list, &count);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_2);
+ if (0 != count) break;
+ }
+
+ if (!_populate_list(list, contact_ids, filters[search_id], uri[search_id], search_id, options->multiple))
+ continue;
+ }
+
+on_error_2:
+ eina_hash_free(contact_ids);
+
+on_error_1:
+ for (int id = 0; id < SEARCH_ID_COUNT; ++id)
+ {
+ if (filters[id])
+ contacts_filter_destroy(filters[id]);
+ }
+
+ return list;
+}
+
+static bool
+_search_records(contacts_filter_h filter,
+ const char *uri,
+ contacts_list_h *list,
+ Eina_Bool multiple)
+{
+ int ret;
+ contacts_query_h query = NULL;
+
+ ret = contacts_query_create(uri, &query);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ ret = contacts_query_set_filter(query, filter);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_1);
+
+ ret = contacts_db_get_records_with_query(query, 0, multiple ? 0 : 1, list);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_1);
+
+ ret = contacts_query_destroy(query);
+ EINA_SAFETY_ON_FALSE_GOTO(CONTACTS_ERROR_NONE == ret, on_error_2);
+ return true;
+
+on_error_2:
+ ret = contacts_list_destroy(*list, true);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+ *list = NULL;
+
+on_error_1:
+ ret = contacts_query_destroy(query);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+ return false;
+}
+
+static bool
+_populate_list(contacts_list_h list,
+ Eina_Hash *contact_ids,
+ contacts_filter_h filter,
+ const char *uri,
+ int search_id,
+ Eina_Bool multiple)
+{
+ contacts_list_h sub_list = NULL;
+ if (!_search_records(filter, uri, &sub_list, multiple))
+ return false;
+
+ unsigned int contact_id[SEARCH_ID_COUNT] = {
+ [SEARCH_CONTACT] = _contacts_contact.id,
+ [SEARCH_ADDRESS] = _contacts_address.contact_id,
+ [SEARCH_EVENT] = _contacts_event.contact_id,
+ [SEARCH_COMPANY] = _contacts_company.contact_id,
+ [SEARCH_EMAIL] = _contacts_email.contact_id,
+ [SEARCH_NAME] = _contacts_name.contact_id,
+ [SEARCH_NICKNAME] = _contacts_nickname.contact_id,
+ [SEARCH_MESSENGER] = _contacts_messenger.contact_id,
+ [SEARCH_NOTE] = _contacts_note.contact_id,
+ [SEARCH_NUMBER] = _contacts_number.contact_id,
+ [SEARCH_URL] = _contacts_url.contact_id,
+ [SEARCH_IMAGE] = _contacts_image.contact_id
+ };
+
+ int ret;
+ bool result = true;
+ do
+ {
+ contacts_record_h record = NULL;
+ ret = contacts_list_get_current_record_p(sub_list, &record);
+ if (CONTACTS_ERROR_NONE != ret || !record)
+ {
+ WRN("contacts_list_get_current_record_p returned %d", ret);
+ break;
+ }
+
+ int id;
+ result = get_int(record, contact_id[search_id], &id);
+ EINA_SAFETY_ON_FALSE_GOTO(result, on_error);
+
+ if (eina_hash_find(contact_ids, &id))
+ continue;
+
+ contacts_record_h contact_record = NULL;
+ result = contacts_db_get_record(uri, id, &contact_record) == CONTACTS_ERROR_NONE;
+ EINA_SAFETY_ON_FALSE_GOTO(result, on_error);
+
+ if (!contact_record) continue;
+
+ result = contacts_list_add(list, contact_record) == CONTACTS_ERROR_NONE;
+ EINA_SAFETY_ON_FALSE_GOTO(result, on_error);
+
+ result = eina_hash_add(contact_ids, &id, &id) == EINA_TRUE;
+ EINA_SAFETY_ON_FALSE_GOTO(result, on_error);
+
+ } while (multiple && contacts_list_next(sub_list) == CONTACTS_ERROR_NONE);
+
+on_error:
+ ret = contacts_list_destroy(sub_list, true);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+ return result;
+}
+
+#include "ecordova_contacts.eo.c"
diff --git a/src/lib/ecordova/ecordova_contacts.eo b/src/lib/ecordova/ecordova_contacts.eo
new file mode 100644
index 0000000000..0c968006ab
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contacts.eo
@@ -0,0 +1,76 @@
+struct Ecordova.Contacts.FindOptions {
+ [[Contact find options]]
+ filter: const(char)*;
+ [[The search string used to find contacts.]]
+
+ multiple: bool;
+ [[used to determine if more than one contact should be returned]]
+
+ desiredFields: list<char*>*;
+ [[Contact fields to be returned back. If specified, the resulting Contact
+ object only features values for these fields. (optional)]]
+}
+
+enum Ecordova.Contacts.Error {
+ UNKNOWN_ERROR = 0,
+ INVALID_ARGUMENT_ERROR = 1,
+ TIMEOUT_ERROR = 2,
+ PENDING_OPERATION_ERROR = 3,
+ IO_ERROR = 4,
+ NOT_SUPPORTED_ERROR = 5,
+ PERMISSION_DENIED_ERROR = 20
+}
+
+class Ecordova.Contacts (Eo.Base) {
+ [[Ecordova Contacts Plugin
+ Plugin ID: org.apache.cordova.contacts
+ http://plugins.cordova.io/#/package/org.apache.cordova.contacts
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_Contacts constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ }
+ find {
+ [[Returns an array of Contacts matching the search criteria.]]
+ params {
+ fields: const(list<char*>)*;
+ [[fields that should be searched]]
+
+ options: const(Ecordova.Contacts.FindOptions)*;
+ [[options that can be applied to contact searching]]
+ }
+ }
+ contact_pick {
+ [[This function picks contact from phone using contact picker UI]]
+ }
+ create {
+ [[This function creates a new contact, but it does not persist the contact
+ to device storage. To persist the contact to device storage, invoke
+ contact.save().
+ ]]
+ params {
+ other: Ecordova.Contact*;
+ [[an object whose properties will be examined to create a new Contact]]
+ }
+ return: Ecordova.Contact*;
+ [[new Contact object]]
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ find,success: const(array<Ecordova.Contact*>)*;
+ pick,success: const(array<Ecordova.Contact*>)*;
+ error: Ecordova.Contacts.Error*;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_contacts_private.h b/src/lib/ecordova/ecordova_contacts_private.h
new file mode 100644
index 0000000000..7a60b2328b
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contacts_private.h
@@ -0,0 +1,16 @@
+#ifndef _ECORDOVA_CONTACTS_PRIVATE_H
+#define _ECORDOVA_CONTACTS_PRIVATE_H
+
+#include "ecordova_private.h"
+
+typedef struct _Ecordova_Contacts_Data Ecordova_Contacts_Data;
+
+/**
+ * Ecordova.Contacts private data
+ */
+struct _Ecordova_Contacts_Data
+{
+ Eo *obj;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_contacts_record_utils.c b/src/lib/ecordova/ecordova_contacts_record_utils.c
new file mode 100644
index 0000000000..09cab89d4f
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contacts_record_utils.c
@@ -0,0 +1,121 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_contacts_record_utils.h"
+
+#include <Eina.h>
+
+bool
+get_str(contacts_record_h record, unsigned int property_id, char **value)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(record, false);
+
+ int ret = contacts_record_get_str(record, property_id, value);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ return true;
+}
+
+bool
+get_str_p(contacts_record_h record, unsigned int property_id, const char **value)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(record, false);
+
+ int ret = contacts_record_get_str_p(record, property_id, (char**)value);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ return true;
+}
+
+bool
+set_str(contacts_record_h record, unsigned int property_id, const char *value)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(record, false);
+
+ int ret = contacts_record_set_str(record, property_id, value);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ return true;
+}
+
+bool
+get_int(contacts_record_h record, unsigned int property_id, int *value)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(record, false);
+
+ int ret = contacts_record_get_int(record, property_id, value);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ return true;
+}
+
+bool
+set_int(contacts_record_h record, unsigned int property_id, int value)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(record, false);
+
+ int ret = contacts_record_set_int(record, property_id, value);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ return true;
+}
+
+bool
+get_bool(contacts_record_h record, unsigned int property_id, Eina_Bool *value)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(record, false);
+
+ bool raw_value;
+ int ret = contacts_record_get_bool(record, property_id, &raw_value);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ *value = raw_value ? EINA_TRUE : EINA_FALSE;
+ return true;
+}
+
+bool
+set_bool(contacts_record_h record, unsigned int property_id, Eina_Bool value)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(record, false);
+
+ int ret = contacts_record_set_bool(record, property_id, (bool)value);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ return true;
+}
+
+bool
+clear_all_contact_record(contacts_record_h contacts_record,
+ unsigned int property_id)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(contacts_record, false);
+
+ int ret;
+ int count = 0;
+ ret = contacts_record_get_child_record_count(contacts_record,
+ property_id,
+ &count);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret ||
+ CONTACTS_ERROR_NO_DATA == ret, false);
+
+ for (int index = count - 1; index >= 0; --index)
+ {
+ contacts_record_h child_record = NULL;
+ ret = contacts_record_get_child_record_at_p(contacts_record,
+ property_id,
+ index,
+ &child_record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ ret = contacts_record_remove_child_record(contacts_record,
+ property_id,
+ child_record);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+
+ ret = contacts_record_destroy(child_record, true);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONTACTS_ERROR_NONE == ret, false);
+ }
+
+ return true;
+}
diff --git a/src/lib/ecordova/ecordova_contacts_record_utils.h b/src/lib/ecordova/ecordova_contacts_record_utils.h
new file mode 100644
index 0000000000..9e9aa2d55e
--- /dev/null
+++ b/src/lib/ecordova/ecordova_contacts_record_utils.h
@@ -0,0 +1,20 @@
+#ifndef _ECORDOVA_CONTACTS_RECORD_UTILS_H
+#define _ECORDOVA_CONTACTS_RECORD_UTILS_H
+
+#include <Eina.h>
+#include <contacts.h>
+#include <stdbool.h>
+
+bool get_str(contacts_record_h, unsigned int, char **);
+bool get_str_p(contacts_record_h, unsigned int, const char **);
+bool set_str(contacts_record_h, unsigned int, const char *);
+
+bool get_int(contacts_record_h, unsigned int, int *);
+bool set_int(contacts_record_h, unsigned int, int);
+
+bool get_bool(contacts_record_h, unsigned int, Eina_Bool *);
+bool set_bool(contacts_record_h, unsigned int, Eina_Bool);
+
+bool clear_all_contact_record(contacts_record_h, unsigned int);
+
+#endif
diff --git a/src/lib/ecordova/ecordova_device.c b/src/lib/ecordova/ecordova_device.c
new file mode 100644
index 0000000000..0971292111
--- /dev/null
+++ b/src/lib/ecordova/ecordova_device.c
@@ -0,0 +1,107 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_device_private.h"
+
+#include <system/system_info.h>
+
+#define MY_CLASS ECORDOVA_DEVICE_CLASS
+#define MY_CLASS_NAME "Ecordova_Device"
+
+static Eo_Base *
+_ecordova_device_eo_base_constructor(Eo *obj, Ecordova_Device_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->uuid = NULL;
+ pd->version = NULL;
+ pd->model = NULL;
+ pd->platform = NULL;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_device_constructor(Eo *obj EINA_UNUSED,
+ Ecordova_Device_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+}
+
+static void
+_ecordova_device_eo_base_destructor(Eo *obj, Ecordova_Device_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ free(pd->uuid);
+ free(pd->version);
+ free(pd->model);
+ free(pd->platform);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static const char *
+_ecordova_device_ecordova_get(Eo *obj EINA_UNUSED,
+ Ecordova_Device_Data *pd EINA_UNUSED)
+{
+ ERR("Not implemented.");
+ return NULL;
+}
+
+static const char *
+_ecordova_device_model_get(Eo *obj EINA_UNUSED, Ecordova_Device_Data *pd)
+{
+ if (!pd->model)
+ {
+ int ret = system_info_get_platform_string("tizen.org/system/model_name",
+ &pd->model);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == SYSTEM_INFO_ERROR_NONE, NULL);
+ }
+
+ return pd->model;
+}
+
+static const char *
+_ecordova_device_platform_get(Eo *obj EINA_UNUSED, Ecordova_Device_Data *pd)
+{
+ if (!pd->model)
+ {
+ int ret = system_info_get_platform_string("tizen.org/system/platform.name",
+ &pd->model);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == SYSTEM_INFO_ERROR_NONE, NULL);
+ }
+
+ return pd->model;
+}
+
+static const char *
+_ecordova_device_uuid_get(Eo *obj EINA_UNUSED, Ecordova_Device_Data *pd)
+{
+ if (!pd->uuid)
+ {
+ int ret = system_info_get_platform_string("tizen.org/system/tizenid",
+ &pd->uuid);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == SYSTEM_INFO_ERROR_NONE, NULL);
+ }
+
+ return pd->uuid;
+}
+
+static const char *
+_ecordova_device_version_get(Eo *obj EINA_UNUSED, Ecordova_Device_Data *pd)
+{
+ if (!pd->version)
+ {
+ // requires http://tizen.org/privilege/system (and not "systeminfo") privileges to be added in config.xml
+ int ret = system_info_get_platform_string("tizen.org/feature/platform.version",
+ &pd->version);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == SYSTEM_INFO_ERROR_NONE, NULL);
+ }
+
+ return pd->version;
+}
+
+#include "ecordova_device.eo.c"
diff --git a/src/lib/ecordova/ecordova_device.eo b/src/lib/ecordova/ecordova_device.eo
new file mode 100644
index 0000000000..8221850c97
--- /dev/null
+++ b/src/lib/ecordova/ecordova_device.eo
@@ -0,0 +1,60 @@
+class Ecordova.Device (Eo.Base) {
+ [[Ecordova Device Plugin
+ Plugin ID: org.apache.cordova.device
+ http://plugins.cordova.io/#/package/org.apache.cordova.device
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_Device constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ }
+ @property ecordova {
+ [[Get the version of Ecordova running on the device.]]
+ get {}
+ values {
+ value: const(char)*;
+ }
+ }
+ @property model {
+ [[Returns the name of the device's model or product. The value is
+ set by the device manufacturer and may be different across
+ versions of the same product.]]
+ get {}
+ values {
+ value: const(char)*;
+ }
+ }
+ @property platform {
+ [[Get the device's operating system name.]]
+ get {}
+ values {
+ value: const(char)*;
+ }
+ }
+ @property uuid {
+ [[Get the device's Universally Unique Identifier (UUID).]]
+ get {}
+ values {
+ value: const(char)*;
+ }
+ }
+ @property version {
+ [[Get the operating system version.]]
+ get {}
+ values {
+ value: const(char)*;
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_device_private.h b/src/lib/ecordova/ecordova_device_private.h
new file mode 100644
index 0000000000..7bed6e5486
--- /dev/null
+++ b/src/lib/ecordova/ecordova_device_private.h
@@ -0,0 +1,20 @@
+#ifndef _ECORDOVA_DEVICE_PRIVATE_H
+#define _ECORDOVA_DEVICE_PRIVATE_H
+
+#include "ecordova_private.h"
+
+typedef struct _Ecordova_Device_Data Ecordova_Device_Data;
+
+/**
+ * Ecordova.Device private data
+ */
+struct _Ecordova_Device_Data
+{
+ Eo *obj;
+ char *uuid;
+ char *version;
+ char *model;
+ char *platform;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_devicemotion.c b/src/lib/ecordova/ecordova_devicemotion.c
new file mode 100644
index 0000000000..3b6543cb42
--- /dev/null
+++ b/src/lib/ecordova/ecordova_devicemotion.c
@@ -0,0 +1,176 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_devicemotion_private.h"
+
+#define MY_CLASS ECORDOVA_DEVICEMOTION_CLASS
+#define MY_CLASS_NAME "Ecordova_DeviceMotion"
+
+static void _on_sensor_event(sensor_h, sensor_event_s *, void *);
+static void _hash_data_free(sensor_listener_h);
+static sensor_listener_h _create_listener(Ecordova_DeviceMotion_Data *);
+
+static Eo_Base *
+_ecordova_devicemotion_eo_base_constructor(Eo *obj,
+ Ecordova_DeviceMotion_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->sensor = NULL;
+ pd->listeners = eina_hash_int32_new(EINA_FREE_CB(_hash_data_free));
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_devicemotion_constructor(Eo *obj EINA_UNUSED,
+ Ecordova_DeviceMotion_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+}
+
+static void
+_ecordova_devicemotion_eo_base_destructor(Eo *obj,
+ Ecordova_DeviceMotion_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ eina_hash_free(pd->listeners);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_devicemotion_current_acceleration_get(Eo *obj,
+ Ecordova_DeviceMotion_Data *pd)
+{
+ sensor_listener_h listener = _create_listener(pd);
+ if (!listener)
+ {
+ eo_do(obj, eo_event_callback_call(ECORDOVA_DEVICEMOTION_EVENT_ERROR,
+ NULL));
+ return;
+ }
+
+ int ret = sensor_listener_start(listener);
+ EINA_SAFETY_ON_FALSE_GOTO(SENSOR_ERROR_NONE == ret, on_error);
+
+ sensor_event_s event;
+ ret = sensor_listener_read_data(listener, &event);
+ EINA_SAFETY_ON_FALSE_GOTO(SENSOR_ERROR_NONE == ret, on_error);
+
+ Ecordova_DeviceMotion_Acceleration acceleration = {
+ .x = event.values[0],
+ .y = event.values[1],
+ .z = event.values[2],
+ .timestamp = event.timestamp
+ };
+ eo_do(obj, eo_event_callback_call(ECORDOVA_DEVICEMOTION_EVENT_CURRENT_SUCCESS,
+ &acceleration));
+
+on_error:
+ ret = sensor_destroy_listener(listener);
+ EINA_SAFETY_ON_FALSE_RETURN(SENSOR_ERROR_NONE == ret);
+}
+
+static Ecordova_DeviceMotion_WatchID
+_ecordova_devicemotion_acceleration_watch(Eo *obj,
+ Ecordova_DeviceMotion_Data *pd,
+ const Ecordova_DeviceMotion_AccelerometerOptions *options)
+{
+ sensor_listener_h listener = _create_listener(pd);
+ if (!listener)
+ {
+ eo_do(obj, eo_event_callback_call(ECORDOVA_DEVICEMOTION_EVENT_ERROR,
+ NULL));
+ return 0;
+ }
+
+ const Ecordova_DeviceMotion_AccelerometerOptions default_options = {
+ .frequency = 10000
+ };
+ if (!options)
+ options = &default_options;
+
+ int ret = sensor_listener_set_event_cb(listener,
+ options->frequency,
+ _on_sensor_event,
+ pd->obj);
+ EINA_SAFETY_ON_FALSE_GOTO(SENSOR_ERROR_NONE == ret, on_error);
+
+ ret = sensor_listener_start(listener);
+ EINA_SAFETY_ON_FALSE_GOTO(SENSOR_ERROR_NONE == ret, on_error);
+
+ static Ecordova_DeviceMotion_WatchID id = 0;
+ ++id;
+ eina_hash_add(pd->listeners, &id, listener);
+ return id;
+
+on_error:
+ ret = sensor_destroy_listener(listener);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(SENSOR_ERROR_NONE == ret, 0);
+ return 0;
+}
+
+static void
+_ecordova_devicemotion_watch_clear(Eo *obj,
+ Ecordova_DeviceMotion_Data *pd,
+ Ecordova_DeviceMotion_WatchID watch_id)
+{
+ sensor_listener_h listener = eina_hash_find(pd->listeners, &watch_id);
+ if (!listener)
+ {
+ eo_do(obj, eo_event_callback_call(ECORDOVA_DEVICEMOTION_EVENT_ERROR,
+ NULL));
+ return;
+ }
+
+ Eina_Bool ret = eina_hash_del(pd->listeners, &watch_id, NULL);
+ EINA_SAFETY_ON_FALSE_RETURN(ret);
+}
+
+static sensor_listener_h
+_create_listener(Ecordova_DeviceMotion_Data *pd)
+{
+ int ret = SENSOR_ERROR_NONE;
+
+ if (!pd->sensor)
+ {
+ ret = sensor_get_default_sensor(SENSOR_ACCELEROMETER, &pd->sensor);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(SENSOR_ERROR_NONE == ret, NULL);
+ }
+
+ sensor_listener_h listener = NULL;
+ ret = sensor_create_listener(pd->sensor, &listener);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(SENSOR_ERROR_NONE == ret, NULL);
+
+ return listener;
+}
+
+static void
+_on_sensor_event(sensor_h sensor EINA_UNUSED,
+ sensor_event_s *event,
+ void *user_data)
+{
+ Eo *obj = user_data;
+
+ Ecordova_DeviceMotion_Acceleration acceleration = {
+ .x = event->values[0],
+ .y = event->values[1],
+ .z = event->values[2],
+ .timestamp = event->timestamp
+ };
+ eo_do(obj, eo_event_callback_call(ECORDOVA_DEVICEMOTION_EVENT_WATCH_SUCCESS,
+ &acceleration));
+}
+
+static void
+_hash_data_free(sensor_listener_h listener)
+{
+ int ret = sensor_destroy_listener(listener);
+ EINA_SAFETY_ON_FALSE_RETURN(SENSOR_ERROR_NONE == ret);
+}
+
+#include "ecordova_devicemotion.eo.c"
diff --git a/src/lib/ecordova/ecordova_devicemotion.eo b/src/lib/ecordova/ecordova_devicemotion.eo
new file mode 100644
index 0000000000..20640d3351
--- /dev/null
+++ b/src/lib/ecordova/ecordova_devicemotion.eo
@@ -0,0 +1,70 @@
+type Ecordova.DeviceMotion.WatchID: int;
+
+struct Ecordova.DeviceMotion.Acceleration {
+ x: double; [[Amount of acceleration on the x-axis. (in m/s^2)]]
+ y: double; [[Amount of acceleration on the y-axis. (in m/s^2)]]
+ z: double; [[Amount of acceleration on the z-axis. (in m/s^2)]]
+ timestamp: time; [[Creation timestamp in milliseconds.]]
+}
+
+struct Ecordova.DeviceMotion.AccelerometerOptions {
+ frequency: int;
+ [[requested period of calls to accelerometerSuccess with acceleration data
+ in Milliseconds. (Default: 10000)]]
+}
+
+class Ecordova.DeviceMotion (Eo.Base) {
+ [[Ecordova Device-Motion Plugin
+ Plugin ID: org.apache.cordova.device-motion
+ http://plugins.cordova.io/#/package/org.apache.cordova.device-motion
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_DeviceMotion constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ params {
+ }
+ }
+ current_acceleration_get {
+ [[Get the current acceleration]]
+ }
+ acceleration_watch {
+ [[Retrieves the device's current Acceleration at a regular
+ interval, executing the accelerometerSuccess callback function
+ each time. Specify the interval in milliseconds via the
+ acceleratorOptions object's frequency parameter.
+ ]]
+ params {
+ options: const(Ecordova.DeviceMotion.AccelerometerOptions)*;
+ }
+ return: Ecordova.DeviceMotion.WatchID;
+ [[references the accelerometer's watch interval, and can be used
+ with navigator.accelerometer.watch_clear to stop watching the
+ accelerometer.
+ ]]
+ }
+ watch_clear {
+ [[Stop watching the Acceleration referenced by the watchID parameter.]]
+ params {
+ watch_id: Ecordova.DeviceMotion.WatchID;
+ [[The ID returned by navigator.accelerometer.acceleration_watch.]]
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ current,success: Ecordova.DeviceMotion.Acceleration*;
+ watch,success: Ecordova.DeviceMotion.Acceleration*;
+ error;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_devicemotion_private.h b/src/lib/ecordova/ecordova_devicemotion_private.h
new file mode 100644
index 0000000000..fb75f4d810
--- /dev/null
+++ b/src/lib/ecordova/ecordova_devicemotion_private.h
@@ -0,0 +1,20 @@
+#ifndef _ECORDOVA_DEVICEMOTION_PRIVATE_H
+#define _ECORDOVA_DEVICEMOTION_PRIVATE_H
+
+#include "ecordova_private.h"
+
+#include <sensor.h>
+
+typedef struct _Ecordova_DeviceMotion_Data Ecordova_DeviceMotion_Data;
+
+/**
+ * Ecordova.DeviceMotion private data
+ */
+struct _Ecordova_DeviceMotion_Data
+{
+ Eo *obj;
+ sensor_h sensor;
+ Eina_Hash *listeners;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_deviceorientation.c b/src/lib/ecordova/ecordova_deviceorientation.c
new file mode 100644
index 0000000000..87a3d65dbe
--- /dev/null
+++ b/src/lib/ecordova/ecordova_deviceorientation.c
@@ -0,0 +1,180 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_deviceorientation_private.h"
+
+#define MY_CLASS ECORDOVA_DEVICEORIENTATION_CLASS
+#define MY_CLASS_NAME "Ecordova_DeviceOrientation"
+
+static void _on_sensor_event(sensor_h, sensor_event_s *, void *);
+static void _hash_data_free(sensor_listener_h);
+static sensor_listener_h _create_listener(Ecordova_DeviceOrientation_Data *);
+
+static Eo_Base *
+_ecordova_deviceorientation_eo_base_constructor(Eo *obj,
+ Ecordova_DeviceOrientation_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->sensor = NULL;
+ pd->listeners = eina_hash_int32_new(EINA_FREE_CB(_hash_data_free));
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_deviceorientation_constructor(Eo *obj EINA_UNUSED,
+ Ecordova_DeviceOrientation_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+}
+
+static void
+_ecordova_deviceorientation_eo_base_destructor(Eo *obj,
+ Ecordova_DeviceOrientation_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ eina_hash_free(pd->listeners);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_deviceorientation_current_heading_get(Eo *obj,
+ Ecordova_DeviceOrientation_Data *pd)
+{
+ sensor_listener_h listener = _create_listener(pd);
+ if (!listener)
+ {
+ Ecordova_DeviceOrientation_Error error = ECORDOVA_DEVICEORIENTATION_ERROR_COMPASS_INTERNAL_ERR;
+ eo_do(obj, eo_event_callback_call(ECORDOVA_DEVICEORIENTATION_EVENT_ERROR,
+ &error));
+ return;
+ }
+
+ int ret = sensor_listener_start(listener);
+ EINA_SAFETY_ON_FALSE_GOTO(SENSOR_ERROR_NONE == ret, on_error);
+
+ sensor_event_s event;
+ ret = sensor_listener_read_data(listener, &event);
+ EINA_SAFETY_ON_FALSE_GOTO(SENSOR_ERROR_NONE == ret, on_error);
+
+ // TODO: check the correct values
+ Ecordova_DeviceOrientation_Heading orientation = {
+ .magnetic_heading = event.values[0],
+ .true_heading = event.values[0],
+ .heading_accuracy = 0,
+ .timestamp = event.timestamp
+ };
+ eo_do(obj, eo_event_callback_call(ECORDOVA_DEVICEORIENTATION_EVENT_CURRENT_SUCCESS,
+ &orientation));
+
+on_error:
+ ret = sensor_destroy_listener(listener);
+ EINA_SAFETY_ON_FALSE_RETURN(SENSOR_ERROR_NONE == ret);
+}
+
+static Ecordova_DeviceOrientation_WatchID
+_ecordova_deviceorientation_heading_watch(Eo *obj,
+ Ecordova_DeviceOrientation_Data *pd,
+ const Ecordova_DeviceOrientation_OrientationOptions *options)
+{
+ sensor_listener_h listener = _create_listener(pd);
+ if (!listener)
+ {
+ Ecordova_DeviceOrientation_Error error = ECORDOVA_DEVICEORIENTATION_ERROR_COMPASS_INTERNAL_ERR;
+ eo_do(obj, eo_event_callback_call(ECORDOVA_DEVICEORIENTATION_EVENT_ERROR,
+ &error));
+ return 0;
+ }
+
+ const Ecordova_DeviceOrientation_OrientationOptions default_options = {
+ .frequency = 100
+ };
+ if (!options)
+ options = &default_options;
+
+ int ret = sensor_listener_set_event_cb(listener,
+ options->frequency,
+ _on_sensor_event,
+ pd->obj);
+ EINA_SAFETY_ON_FALSE_GOTO(SENSOR_ERROR_NONE == ret, on_error);
+
+ ret = sensor_listener_start(listener);
+ EINA_SAFETY_ON_FALSE_GOTO(SENSOR_ERROR_NONE == ret, on_error);
+
+ static Ecordova_DeviceOrientation_WatchID id = 0;
+ ++id;
+ eina_hash_add(pd->listeners, &id, listener);
+ return id;
+
+on_error:
+ ret = sensor_destroy_listener(listener);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(SENSOR_ERROR_NONE == ret, 0);
+ return 0;
+}
+
+static void
+_ecordova_deviceorientation_watch_clear(Eo *obj,
+ Ecordova_DeviceOrientation_Data *pd,
+ Ecordova_DeviceOrientation_WatchID watch_id)
+{
+ sensor_listener_h listener = eina_hash_find(pd->listeners, &watch_id);
+ if (!listener)
+ {
+ eo_do(obj, eo_event_callback_call(ECORDOVA_DEVICEORIENTATION_EVENT_ERROR,
+ NULL));
+ return;
+ }
+
+ Eina_Bool ret = eina_hash_del(pd->listeners, &watch_id, NULL);
+ EINA_SAFETY_ON_FALSE_RETURN(ret);
+}
+
+static sensor_listener_h
+_create_listener(Ecordova_DeviceOrientation_Data *pd)
+{
+ int ret = SENSOR_ERROR_NONE;
+
+ if (!pd->sensor)
+ {
+ ret = sensor_get_default_sensor(SENSOR_ORIENTATION, &pd->sensor);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(SENSOR_ERROR_NONE == ret, NULL);
+ }
+
+ sensor_listener_h listener = NULL;
+ ret = sensor_create_listener(pd->sensor, &listener);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(SENSOR_ERROR_NONE == ret, NULL);
+
+ return listener;
+}
+
+static void
+_on_sensor_event(sensor_h sensor EINA_UNUSED,
+ sensor_event_s *event,
+ void *user_data)
+{
+ Eo *obj = user_data;
+
+ // TODO: check the correct values
+ Ecordova_DeviceOrientation_Heading orientation = {
+ .magnetic_heading = event->values[0],
+ .true_heading = event->values[0],
+ .heading_accuracy = 0,
+ .timestamp = event->timestamp
+ };
+ eo_do(obj, eo_event_callback_call(ECORDOVA_DEVICEORIENTATION_EVENT_WATCH_SUCCESS,
+ &orientation));
+}
+
+static void
+_hash_data_free(sensor_listener_h listener)
+{
+ int ret = sensor_destroy_listener(listener);
+ EINA_SAFETY_ON_FALSE_RETURN(SENSOR_ERROR_NONE == ret);
+}
+
+#include "ecordova_deviceorientation.eo.c"
diff --git a/src/lib/ecordova/ecordova_deviceorientation.eo b/src/lib/ecordova/ecordova_deviceorientation.eo
new file mode 100644
index 0000000000..edf3b4a6c2
--- /dev/null
+++ b/src/lib/ecordova/ecordova_deviceorientation.eo
@@ -0,0 +1,87 @@
+type Ecordova.DeviceOrientation.WatchID: int;
+
+struct Ecordova.DeviceOrientation.Heading {
+ magnetic_heading: double;
+ [[The heading in degrees from 0-359.99 at a single moment in time.]]
+
+ true_heading: double;
+ [[The heading relative to the geographic North Pole in degrees 0-359.99 at a
+ single moment in time. A negative value indicates that the true heading
+ can't be determined.]]
+
+ heading_accuracy: double;
+ [[The deviation in degrees between the reported heading and the true heading.]]
+
+ timestamp: time;
+ [[The time at which this heading was determined. (milliseconds)]]
+}
+
+struct Ecordova.DeviceOrientation.OrientationOptions {
+ frequency: int;
+ [[How often to retrieve the compass heading in milliseconds. (Default: 100)]]
+
+ filter: double;
+ [[The change in degrees required to initiate a heading_watch success
+ callback. When this value is set, frequency is ignored.]]
+}
+
+enum Ecordova.DeviceOrientation.Error {
+ COMPASS_INTERNAL_ERR = 0,
+ COMPASS_NOT_SUPPORTED = 20
+}
+
+class Ecordova.DeviceOrientation (Eo.Base) {
+ [[Ecordova Device-Orientation Plugin
+ Plugin ID: org.apache.cordova.device-orientation
+ http://plugins.cordova.io/#/package/org.apache.cordova.device-orientation
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_DeviceOrientation constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ }
+ current_heading_get {
+ [[Get the current compass heading. The compass heading is returned
+ via a CompassHeading object using the compassSuccess callback
+ function.
+ ]]
+ }
+ heading_watch {
+ [[Gets the device's current heading at a regular interval. Each
+ time the heading is retrieved, the headingSuccess callback
+ function is executed.
+ ]]
+ params {
+ options: const(Ecordova.DeviceOrientation.OrientationOptions)*;
+ }
+ return: Ecordova.DeviceOrientation.WatchID;
+ [[references the compass watch interval. The watch ID can be used
+ with navigator.compass.watch_clear to stop watching the
+ navigator.compass.
+ ]]
+ }
+ watch_clear {
+ [[Stop watching the compass referenced by the watch ID parameter.]]
+ params {
+ watch_id: Ecordova.DeviceOrientation.WatchID;
+ [[The ID returned by navigator.compass.heading_watch.]]
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ current,success: Ecordova.DeviceOrientation.Heading*;
+ watch,success: Ecordova.DeviceOrientation.Heading*;
+ error: Ecordova.DeviceOrientation.Error;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_deviceorientation_private.h b/src/lib/ecordova/ecordova_deviceorientation_private.h
new file mode 100644
index 0000000000..a2f1c6dfea
--- /dev/null
+++ b/src/lib/ecordova/ecordova_deviceorientation_private.h
@@ -0,0 +1,20 @@
+#ifndef _ECORDOVA_DEVICEORIENTATION_PRIVATE_H
+#define _ECORDOVA_DEVICEORIENTATION_PRIVATE_H
+
+#include "ecordova_private.h"
+
+#include <sensor.h>
+
+typedef struct _Ecordova_DeviceOrientation_Data Ecordova_DeviceOrientation_Data;
+
+/**
+ * Ecordova.DeviceOrientation private data
+ */
+struct _Ecordova_DeviceOrientation_Data
+{
+ Eo *obj;
+ sensor_h sensor;
+ Eina_Hash *listeners;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_dialogs.c b/src/lib/ecordova/ecordova_dialogs.c
new file mode 100644
index 0000000000..96b660ad9d
--- /dev/null
+++ b/src/lib/ecordova/ecordova_dialogs.c
@@ -0,0 +1,75 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_dialogs_private.h"
+
+#define MY_CLASS ECORDOVA_DIALOGS_CLASS
+#define MY_CLASS_NAME "Ecordova_Dialogs"
+
+static Eo_Base *
+_ecordova_dialogs_eo_base_constructor(Eo *obj, Ecordova_Dialogs_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_dialogs_constructor(Eo *obj EINA_UNUSED,
+ Ecordova_Dialogs_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+}
+
+static void
+_ecordova_dialogs_eo_base_destructor(Eo *obj,
+ Ecordova_Dialogs_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_dialogs_alert(Eo *obj EINA_UNUSED,
+ Ecordova_Dialogs_Data *pd EINA_UNUSED,
+ const char *message EINA_UNUSED,
+ const char *title EINA_UNUSED,
+ Eina_List *buttons EINA_UNUSED)
+{
+ ERR("Not implemented.");
+}
+
+static void
+_ecordova_dialogs_confirm(Eo *obj EINA_UNUSED,
+ Ecordova_Dialogs_Data *pd EINA_UNUSED,
+ const char *message EINA_UNUSED,
+ const char *title EINA_UNUSED,
+ Eina_List *buttons EINA_UNUSED)
+{
+ ERR("Not implemented.");
+}
+
+static void
+_ecordova_dialogs_prompt(Eo *obj EINA_UNUSED,
+ Ecordova_Dialogs_Data *pd EINA_UNUSED,
+ const char *message EINA_UNUSED,
+ const char *title EINA_UNUSED,
+ Eina_List *buttons EINA_UNUSED,
+ const char *default_text EINA_UNUSED)
+{
+ ERR("Not implemented.");
+}
+
+static void
+_ecordova_dialogs_beep(Eo *obj EINA_UNUSED,
+ Ecordova_Dialogs_Data *pd EINA_UNUSED,
+ int times EINA_UNUSED)
+{
+ ERR("Not implemented.");
+}
+
+#include "ecordova_dialogs.eo.c"
diff --git a/src/lib/ecordova/ecordova_dialogs.eo b/src/lib/ecordova/ecordova_dialogs.eo
new file mode 100644
index 0000000000..4f51b20b46
--- /dev/null
+++ b/src/lib/ecordova/ecordova_dialogs.eo
@@ -0,0 +1,87 @@
+struct Ecordova_Dialogs_PromptCallback {
+ button_index: int;
+ [[The index of the pressed button. (Number) Note that the index uses
+ one-based indexing, so the value is 1, 2, 3, etc.]]
+
+ input1: const(char)*;
+ [[The text entered in the prompt dialog box.]]
+}
+
+class Ecordova.Dialogs (Eo.Base) {
+ [[Ecordova Dialogs Plugin
+ Plugin ID: org.apache.cordova.dialogs
+ http://plugins.cordova.io/#/package/org.apache.cordova.dialogs
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_Dialogs constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ }
+ alert {
+ params {
+ message: const(char)*;
+ [[Dialog message.]]
+
+ title: const(char)*;
+ [[Dialog title (Optional, defaults to 'Alert').]]
+
+ buttons: list<const(char)*>*;
+ [[Button names (Optional, defaults to OK)]]
+ }
+ }
+ confirm {
+ params {
+ message: const(char)*;
+ [[Dialog message.]]
+
+ title: const(char)*;
+ [[Dialog title (Optional, defaults to 'Confirm').]]
+
+ buttons: list<const(char)*>*;
+ [[Button names (Optional, defaults to [OK,Cancel])]]
+ }
+ }
+ prompt {
+ params {
+ message: const(char)*;
+ [[Dialog message.]]
+
+ title: const(char)*;
+ [[Dialog title (Optional, defaults to 'Prompt').]]
+
+ buttons: list<const(char)*>*;
+ [[Button names (Optional, defaults to [OK,Cancel])]]
+
+ default_text: const(char)*;
+ [[Default textbox input value (Optional, Default: empty string)]]
+ }
+ }
+ beep {
+ [[The device plays a beep sound.]]
+ params {
+ times: int; [[The number of times to repeat the beep.]]
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ alert;
+ [[Callback to invoke when alert dialog is dismissed.]]
+
+ confirm: int;
+ [[Callback to invoke with index of button pressed (1, 2, or 3) or when
+ the dialog is dismissed without a button press (0).]]
+
+ prompt: Ecordova_Dialogs_PromptCallback;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_dialogs_private.h b/src/lib/ecordova/ecordova_dialogs_private.h
new file mode 100644
index 0000000000..3bc664ee45
--- /dev/null
+++ b/src/lib/ecordova/ecordova_dialogs_private.h
@@ -0,0 +1,16 @@
+#ifndef _ECORDOVA_DIALOGS_PRIVATE_H
+#define _ECORDOVA_DIALOGS_PRIVATE_H
+
+#include "ecordova_private.h"
+
+typedef struct _Ecordova_Dialogs_Data Ecordova_Dialogs_Data;
+
+/**
+ * Ecordova.Dialogs private data
+ */
+struct _Ecordova_Dialogs_Data
+{
+ Eo *obj;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_directoryentry.c b/src/lib/ecordova/ecordova_directoryentry.c
new file mode 100644
index 0000000000..44d6de7e60
--- /dev/null
+++ b/src/lib/ecordova/ecordova_directoryentry.c
@@ -0,0 +1,324 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_directoryentry_private.h"
+#include "ecordova_entry_private.h"
+
+#include <Ecore_File.h>
+
+#include <stdio.h>
+
+#define MY_CLASS ECORDOVA_DIRECTORYENTRY_CLASS
+#define MY_CLASS_NAME "Ecordova_DirectoryEntry"
+
+static void _remove_notify(Eo *, void *);
+static bool _is_absolute(const char *);
+static void _directory_get(Eo *, void *);
+static void _file_get(Eo *, void *);
+static void _eio_directory_get_cb(void *, Eio_File *, const Eina_Stat *);
+static void _eio_file_get_cb(void *, Eio_File *, const Eina_Stat *);
+static void _eio_create_directory_cb(void *, Eio_File *, int);
+static void _eio_fail_if_path_exists_cb(void *, Eio_File *, const Eina_Stat *);
+static void _eio_mkdir_cb(void *, Eio_File *);
+static void _set_data_path_name_native(Eio_Operation_Data *, const char *);
+static void _eio_create_file_cb(void *, Eio_File *, int);
+
+static Eo_Base *
+_ecordova_directoryentry_eo_base_constructor(Eo *obj,
+ Ecordova_DirectoryEntry_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_directoryentry_constructor(Eo *obj,
+ Ecordova_DirectoryEntry_Data *pd EINA_UNUSED,
+ const char *name,
+ const char *path,
+ Ecordova_FileSystem *file_system,
+ const char *url)
+{
+ DBG("(%p)", obj);
+ eo_do_super(obj, MY_CLASS, ecordova_entry_constructor(EINA_FALSE,
+ EINA_TRUE,
+ name,
+ path,
+ file_system,
+ url));
+}
+
+static void
+_ecordova_directoryentry_eo_base_destructor(Eo *obj EINA_UNUSED,
+ Ecordova_DirectoryEntry_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static Ecordova_DirectoryReader *
+_ecordova_directoryentry_reader_create(Eo *obj,
+ Ecordova_DirectoryEntry_Data *pd EINA_UNUSED)
+{
+ Ecordova_Entry_Data *super = eo_data_scope_get(obj, ECORDOVA_ENTRY_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(super, NULL);
+
+ return eo_add(ECORDOVA_DIRECTORYREADER_CLASS, NULL,
+ ecordova_directoryreader_constructor(super->native));
+}
+
+static void
+_ecordova_directoryentry_directory_get(Eo *obj,
+ Ecordova_DirectoryEntry_Data *pd EINA_UNUSED,
+ const char *path,
+ Ecordova_FileFlags flags)
+{
+ DBG("(%p)", obj);
+ EINA_SAFETY_ON_NULL_RETURN(path);
+
+ Ecordova_Entry_Data *super = eo_data_scope_get(obj, ECORDOVA_ENTRY_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN(super);
+
+ Eio_Operation_Data *data = _data_new(super, _directory_get, _error_notify);
+ _set_data_path_name_native(data, path);
+
+ Eio_Stat_Cb eio_stat_cb = _eio_directory_get_cb;
+ Eio_Error_Cb eio_error_cb = _eio_error_cb;
+
+ if (ECORDOVA_FILEFLAGS_CREATE & flags)
+ {
+ eio_error_cb = _eio_create_directory_cb;
+ if (ECORDOVA_FILEFLAGS_EXCLUSIVE & flags)
+ eio_stat_cb = _eio_fail_if_path_exists_cb;
+ }
+
+ super->pending = eina_list_append(super->pending, data);
+
+ data->file = eio_file_direct_stat(data->native,
+ eio_stat_cb,
+ eio_error_cb,
+ data);
+ EINA_SAFETY_ON_NULL_RETURN(data->file);
+}
+
+static void
+_eio_directory_get_cb(void *user_data,
+ Eio_File *handler EINA_UNUSED,
+ const Eina_Stat *stat EINA_UNUSED)
+{
+ Eio_Operation_Data *data = user_data;
+ DBG("(%p)", data->pd->obj);
+ Ecordova_DirectoryEntry *directory = eo_add(ECORDOVA_DIRECTORYENTRY_CLASS, NULL,
+ ecordova_directoryentry_constructor(data->name, data->path, NULL, data->native)); // TODO: filesystem?
+
+ data->success_cb(data->pd->obj, directory);
+ _data_free(data);
+}
+
+static void
+_eio_file_get_cb(void *user_data,
+ Eio_File *handler EINA_UNUSED,
+ const Eina_Stat *stat EINA_UNUSED)
+{
+ Eio_Operation_Data *data = user_data;
+ Ecordova_FileEntry *file = eo_add(ECORDOVA_FILEENTRY_CLASS, NULL,
+ ecordova_fileentry_constructor(data->name, data->path, NULL, data->native)); // TODO: filesystem?
+
+ data->success_cb(data->pd->obj, file);
+ _data_free(data);
+}
+
+static void
+_eio_fail_if_path_exists_cb(void *user_data,
+ Eio_File *handler EINA_UNUSED,
+ const Eina_Stat *stat EINA_UNUSED)
+{
+ Eio_Operation_Data *data = user_data;
+ DBG("(%p)", data->pd->obj);
+ Ecordova_FileError file_error = ECORDOVA_FILEERROR_PATH_EXISTS_ERR;
+ eo_do(data->pd->obj,
+ eo_event_callback_call(ECORDOVA_ENTRY_EVENT_ERROR, &file_error));
+ _data_free(data);
+}
+
+static void
+_eio_create_directory_cb(void *user_data,
+ Eio_File *handler EINA_UNUSED,
+ int error)
+{
+ Eio_Operation_Data *data = user_data;
+ DBG("(%p)", data->pd->obj);
+ if (ENOENT != error)
+ {
+ _error_notify(data->pd->obj, error);
+ _data_free(data);
+ return;
+ }
+
+ data->file = eio_file_mkdir(data->native,
+ 0777,
+ _eio_mkdir_cb,
+ _eio_error_cb,
+ data);
+}
+
+static void
+_eio_create_file_cb(void *user_data,
+ Eio_File *handler EINA_UNUSED,
+ int error)
+{
+ Eio_Operation_Data *data = user_data;
+ DBG("(%p)", data->pd->obj);
+ if (ENOENT != error)
+ {
+ _error_notify(data->pd->obj, error);
+ _data_free(data);
+ return;
+ }
+
+ // TODO: Create the file in a background thread
+ FILE *fd = fopen(data->native, "ab+");
+ if (!fd)
+ {
+ _error_notify(data->pd->obj, errno);
+ _data_free(data);
+ return;
+ }
+ fclose(fd);
+
+ Ecordova_FileEntry *file = eo_add(ECORDOVA_FILEENTRY_CLASS, NULL,
+ ecordova_fileentry_constructor(data->name, data->path, NULL, data->native)); // TODO: filesystem?
+ data->success_cb(data->pd->obj, file);
+ _data_free(data);
+}
+
+static void
+_eio_mkdir_cb(void *user_data, Eio_File *handler EINA_UNUSED)
+{
+ Eio_Operation_Data *data = user_data;
+ DBG("(%p)", data->pd->obj);
+ Ecordova_DirectoryEntry *directory = eo_add(ECORDOVA_DIRECTORYENTRY_CLASS, NULL,
+ ecordova_directoryentry_constructor(data->name, data->path, NULL, data->native)); // TODO: filesystem?
+ data->success_cb(data->pd->obj, directory);
+ _data_free(data);
+}
+
+static void
+_directory_get(Eo *obj, void *data)
+{
+ Ecordova_DirectoryEntry *directory = data;
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_DIRECTORYENTRY_EVENT_DIRECTORY_GET, directory));
+ eo_unref(directory);
+}
+
+static void
+_file_get(Eo *obj, void *data)
+{
+ Ecordova_FileEntry *file = data;
+ eo_do(obj, eo_event_callback_call(ECORDOVA_DIRECTORYENTRY_EVENT_FILE_GET, file));
+ eo_unref(file);
+}
+
+static void
+_ecordova_directoryentry_recursively_remove(Eo *obj,
+ Ecordova_DirectoryEntry_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+
+ Ecordova_Entry_Data *super = eo_data_scope_get(obj, ECORDOVA_ENTRY_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN(super);
+
+ _entry_remove(super, _remove_notify, _error_notify, true);
+}
+
+static void
+_ecordova_directoryentry_file_get(Eo *obj,
+ Ecordova_DirectoryEntry_Data *pd EINA_UNUSED,
+ const char *path,
+ Ecordova_FileFlags flags)
+{
+ EINA_SAFETY_ON_NULL_RETURN(path);
+ DBG("(%p) path=%s", obj, path);
+
+ Ecordova_Entry_Data *super = eo_data_scope_get(obj, ECORDOVA_ENTRY_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN(super);
+
+ Eio_Operation_Data *data = _data_new(super, _file_get, _error_notify);
+ _set_data_path_name_native(data, path);
+
+ Eio_Stat_Cb eio_stat_cb = _eio_file_get_cb;
+ Eio_Error_Cb eio_error_cb = _eio_error_cb;
+
+ if (ECORDOVA_FILEFLAGS_CREATE & flags)
+ {
+ eio_error_cb = _eio_create_file_cb;
+ if (ECORDOVA_FILEFLAGS_EXCLUSIVE & flags)
+ eio_stat_cb = _eio_fail_if_path_exists_cb;
+ }
+
+ super->pending = eina_list_append(super->pending, data);
+
+ data->file = eio_file_direct_stat(data->native,
+ eio_stat_cb,
+ eio_error_cb,
+ data);
+}
+
+static void
+_remove_notify(Eo *obj, void *data EINA_UNUSED)
+{
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_DIRECTORYENTRY_EVENT_REMOVE_SUCCESS, NULL));
+}
+
+static bool
+_is_absolute(const char *path)
+{
+ // TODO: not multiplatform
+ return path[0] == '/';
+}
+
+static void
+_set_data_path_name_native(Eio_Operation_Data *data, const char *path)
+{
+ EINA_SAFETY_ON_NULL_RETURN(data);
+ EINA_SAFETY_ON_NULL_RETURN(path);
+ split_path(data->pd->native, path, &data->path, &data->name, &data->native);
+}
+
+void
+split_path(const char *working_dir,
+ const char *path,
+ char **dir,
+ char **name,
+ char **url)
+{
+ EINA_SAFETY_ON_NULL_RETURN(path);
+ EINA_SAFETY_ON_NULL_RETURN(dir);
+ EINA_SAFETY_ON_NULL_RETURN(name);
+ EINA_SAFETY_ON_NULL_RETURN(url);
+
+ if (!working_dir || _is_absolute(path))
+ *url = eina_file_path_sanitize(path);
+ else
+ {
+ size_t len = strlen(working_dir) + 1 + strlen(path) + 1;
+ char buffer[len];
+ snprintf(buffer, len, "%s/%s", working_dir, path); // TODO: path separator ?
+ *url = eina_file_path_sanitize(buffer);
+ }
+
+ const char *nameonly = ecore_file_file_get(*url);
+ EINA_SAFETY_ON_NULL_RETURN(nameonly);
+ *name = strdup(nameonly);
+
+ *dir = ecore_file_dir_get(*url);
+}
+
+#include "ecordova_directoryentry.eo.c"
diff --git a/src/lib/ecordova/ecordova_directoryentry.eo b/src/lib/ecordova/ecordova_directoryentry.eo
new file mode 100644
index 0000000000..d751d1d3a5
--- /dev/null
+++ b/src/lib/ecordova/ecordova_directoryentry.eo
@@ -0,0 +1,75 @@
+enum Ecordova_FileFlags {
+ CREATE = 1,
+ EXCLUSIVE = 2
+}
+
+class Ecordova.DirectoryEntry (Ecordova.Entry) {
+ [[An interface representing a directory on the file system.]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_DirectoryEntry constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ params {
+ name: const(char)*;
+ [[name of the directory, excluding the path leading to it]]
+
+ path: const(char)*;
+ [[the absolute full path to the directory]]
+
+ file_system: Ecordova.FileSystem*;
+ [[filesystem on which the directory resides]]
+
+ url: const(char)*;
+ [[an alternate URL which can be used by native webview
+ controls, for example media players.]]
+ }
+ }
+ reader_create {
+ [[Creates a new DirectoryReader to read entries from this directory]]
+ return: own(Ecordova.DirectoryReader*);
+ }
+ directory_get {
+ [[Creates or looks up a directory]]
+ params {
+ path: const(char)*;
+ [[either a relative or absolute path from this directory in
+ which to look up or create a directory]]
+
+ flags: Ecordova_FileFlags;
+ [[options to create or exclusively create the directory]]
+ }
+ }
+ recursively_remove {
+ [[Deletes a directory and all of it's contents]]
+ }
+ file_get {
+ [[Creates or looks up a file]]
+ params {
+ path: const(char)*;
+ [[either a relative or absolute path from this directory in
+ which to look up or create a file]]
+
+ flags: Ecordova_FileFlags;
+ [[options to create or exclusively create the file]]
+
+ }
+ }
+
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ directory,get: Ecordova.DirectoryEntry*;
+ remove,success; [[called with no parameters]]
+ file,get: Ecordova.FileEntry*;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_directoryentry_private.h b/src/lib/ecordova/ecordova_directoryentry_private.h
new file mode 100644
index 0000000000..2a5ac5472b
--- /dev/null
+++ b/src/lib/ecordova/ecordova_directoryentry_private.h
@@ -0,0 +1,18 @@
+#ifndef _ECORDOVA_DIRECTORYENTRY_PRIVATE_H
+#define _ECORDOVA_DIRECTORYENTRY_PRIVATE_H
+
+#include "ecordova_private.h"
+
+typedef struct _Ecordova_DirectoryEntry_Data Ecordova_DirectoryEntry_Data;
+
+/**
+ * Ecordova.DirectoryEntry private data
+ */
+struct _Ecordova_DirectoryEntry_Data
+{
+ Eo *obj;
+};
+
+void split_path(const char *, const char *, char **, char **, char **);
+
+#endif
diff --git a/src/lib/ecordova/ecordova_directoryreader.c b/src/lib/ecordova/ecordova_directoryreader.c
new file mode 100644
index 0000000000..b92fcc9f50
--- /dev/null
+++ b/src/lib/ecordova/ecordova_directoryreader.c
@@ -0,0 +1,161 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_directoryreader_private.h"
+#include "ecordova_entry_private.h"
+
+#define MY_CLASS ECORDOVA_DIRECTORYREADER_CLASS
+#define MY_CLASS_NAME "Ecordova_DirectoryReader"
+
+typedef struct
+{
+ Ecordova_DirectoryReader_Data *pd;
+ Eio_File *file;
+ Eina_List *entries;
+} DirectoryReader_Data;
+
+static Eina_Bool _filter_cb(void *, Eio_File *, const Eina_File_Direct_Info *);
+static void _main_cb(void *, Eio_File *, const Eina_File_Direct_Info *);
+static void _done_cb(void *, Eio_File *);
+static void _error_cb(void *, Eio_File *, int);
+static void _directory_data_free(DirectoryReader_Data *);
+
+static Eo_Base *
+_ecordova_directoryreader_eo_base_constructor(Eo *obj,
+ Ecordova_DirectoryReader_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->native = NULL;
+ pd->pending = NULL;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_directoryreader_constructor(Eo *obj,
+ Ecordova_DirectoryReader_Data *pd,
+ const char *native)
+{
+ DBG("(%p) url=%s", obj, native);
+ pd->native = strdup(native);
+}
+
+static void
+_ecordova_directoryreader_eo_base_destructor(Eo *obj,
+ Ecordova_DirectoryReader_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ free(pd->native);
+
+ DirectoryReader_Data *data;
+ EINA_LIST_FREE(pd->pending, data)
+ {
+ eio_file_cancel(data->file);
+ _directory_data_free(data);
+ }
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_directoryreader_entries_read(Eo *obj,
+ Ecordova_DirectoryReader_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ DirectoryReader_Data *data = calloc(1, sizeof(DirectoryReader_Data));
+ data->pd = pd;
+ data->file = eio_file_stat_ls(pd->native,
+ _filter_cb,
+ _main_cb,
+ _done_cb,
+ _error_cb,
+ data);
+
+ pd->pending = eina_list_append(pd->pending, data);
+}
+
+static Eina_Bool
+_filter_cb(void *data EINA_UNUSED,
+ Eio_File *handler EINA_UNUSED,
+ const Eina_File_Direct_Info *info EINA_UNUSED)
+{
+ return EINA_TRUE;
+}
+
+static void
+_main_cb(void *user_data,
+ Eio_File *handler EINA_UNUSED,
+ const Eina_File_Direct_Info *info)
+{
+ DirectoryReader_Data *data = user_data;
+ Ecordova_Entry *entry = NULL;
+
+ size_t len = info->path_length - info->name_length - 1;
+ char path[len + 1];
+ strncpy(path, info->path, len);
+ path[len] = '\0';
+
+ const char *name = &info->path[info->name_start];
+
+ switch (info->type)
+ {
+ case EINA_FILE_DIR:
+ {
+ entry = eo_add(ECORDOVA_DIRECTORYENTRY_CLASS, NULL,
+ ecordova_directoryentry_constructor(name, path, NULL, info->path)); // TODO: filesystem?
+ break;
+ }
+ case EINA_FILE_REG:
+ {
+ entry = eo_add(ECORDOVA_FILEENTRY_CLASS, NULL,
+ ecordova_fileentry_constructor(name, path, NULL, info->path)); // TODO: filesystem?
+ break;
+ }
+ // TODO: case EINA_FILE_LNK ?
+ default: break;
+ }
+
+ if (entry)
+ data->entries = eina_list_append(data->entries, entry);
+}
+
+static void
+_done_cb(void *user_data, Eio_File *handler EINA_UNUSED)
+{
+ DirectoryReader_Data *data = user_data;
+ data->pd->pending = eina_list_remove(data->pd->pending, data);
+
+ eo_do(data->pd->obj,
+ eo_event_callback_call(ECORDOVA_DIRECTORYREADER_EVENT_SUCCESS,
+ data->entries));
+ _directory_data_free(data);
+}
+
+static void
+_error_cb(void *user_data, Eio_File *handler EINA_UNUSED, int error)
+{
+ DirectoryReader_Data *data = user_data;
+ data->pd->pending = eina_list_remove(data->pd->pending, data);
+
+ Ecordova_FileError file_error = _translate_errno(error);
+ eo_do(data->pd->obj,
+ eo_event_callback_call(ECORDOVA_DIRECTORYREADER_EVENT_ERROR,
+ &file_error));
+ _directory_data_free(data);
+}
+
+static void
+_directory_data_free(DirectoryReader_Data *data)
+{
+ Ecordova_Entry *entry;
+ EINA_LIST_FREE(data->entries, entry)
+ eo_unref(entry);
+ free(data);
+}
+
+#include "ecordova_directoryreader.eo.c"
diff --git a/src/lib/ecordova/ecordova_directoryreader.eo b/src/lib/ecordova/ecordova_directoryreader.eo
new file mode 100644
index 0000000000..e8c6428136
--- /dev/null
+++ b/src/lib/ecordova/ecordova_directoryreader.eo
@@ -0,0 +1,32 @@
+struct ProgressEvent;
+
+class Ecordova.DirectoryReader (Eo.Base) {
+ [[An interface that lists the files and directories in a directory.]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_DirectoryReader constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ params {
+ native: const(char)*;
+ }
+ }
+ entries_read {
+ [[Returns a list of entries from a directory.]]
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ success: const(list<Ecordova.Entry*>*); [[called with a list of entries]]
+ error: const(Ecordova_FileError)*; [[called with a FileError]]
+ }
+}
diff --git a/src/lib/ecordova/ecordova_directoryreader_private.h b/src/lib/ecordova/ecordova_directoryreader_private.h
new file mode 100644
index 0000000000..b12467cbf5
--- /dev/null
+++ b/src/lib/ecordova/ecordova_directoryreader_private.h
@@ -0,0 +1,18 @@
+#ifndef _ECORDOVA_DIRECTORYREADER_PRIVATE_H
+#define _ECORDOVA_DIRECTORYREADER_PRIVATE_H
+
+#include "ecordova_private.h"
+
+typedef struct _Ecordova_DirectoryReader_Data Ecordova_DirectoryReader_Data;
+
+/**
+ * Ecordova.DirectoryReader private data
+ */
+struct _Ecordova_DirectoryReader_Data
+{
+ Eo *obj;
+ char *native;
+ Eina_List *pending;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_entry.c b/src/lib/ecordova/ecordova_entry.c
new file mode 100644
index 0000000000..ed5acb9f50
--- /dev/null
+++ b/src/lib/ecordova/ecordova_entry.c
@@ -0,0 +1,506 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_entry_private.h"
+#include "ecordova_directoryentry_private.h"
+
+#define MY_CLASS ECORDOVA_ENTRY_CLASS
+#define MY_CLASS_NAME "Ecordova_Entry"
+
+static void _eio_stat_cb(void *, Eio_File *, const Eina_Stat *);
+static void _eio_moved_cb(void *, Eio_File *);
+static void _eio_copied_cb(void *, Eio_File *);
+static void _metadata_notify(Eo *, void *);
+static void _move_notify(Eo *, void *);
+static void _copy_notify(Eo *, void *);
+static void _remove_notify(Eo *, void *);
+static Eina_Bool _eio_remove_non_recursively_filter_cb(void *, Eio_File *, const Eina_File_Direct_Info *);
+static void _parent_get_cb(void *, Eio_File *, const Eina_Stat *);
+static void _parent_get_notify(Eo *, void *);
+
+static Eo_Base *
+_ecordova_entry_eo_base_constructor(Eo *obj, Ecordova_Entry_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->name = NULL;
+ pd->path = NULL;
+ pd->file_system = NULL;
+ pd->native = NULL;
+ pd->pending = NULL;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_entry_constructor(Eo *obj,
+ Ecordova_Entry_Data *pd,
+ Eina_Bool file_is,
+ Eina_Bool directory_is,
+ const char *name,
+ const char *path,
+ Ecordova_FileSystem *file_system,
+ const char *url)
+{
+ EINA_SAFETY_ON_NULL_RETURN(name);
+ EINA_SAFETY_ON_NULL_RETURN(path);
+ //EINA_SAFETY_ON_NULL_RETURN(file_system);
+ EINA_SAFETY_ON_NULL_RETURN(url);
+ DBG("(%p) name=%s, path=%s, url=%s", obj, name, path, url);
+
+ pd->is_file = file_is;
+ pd->is_directory = directory_is;
+ pd->name = strdup(name);
+ pd->path = strdup(path);
+ pd->file_system = eo_ref(file_system);
+ pd->native = strdup(url);
+}
+
+static void
+_ecordova_entry_eo_base_destructor(Eo *obj, Ecordova_Entry_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ free(pd->name);
+ free(pd->path);
+ eo_unref(pd->file_system);
+ free(pd->native);
+
+ Eio_Operation_Data *data;
+ EINA_LIST_FREE(pd->pending, data)
+ {
+ eio_file_cancel(data->file);
+ _data_free(data);
+ }
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_entry_metadata_get(Eo *obj EINA_UNUSED, Ecordova_Entry_Data *pd)
+{
+ DBG("(%p)", obj);
+ _metadata_get(pd, _metadata_notify, _error_notify);
+}
+
+static void
+_ecordova_entry_metadata_set(Eo *obj EINA_UNUSED,
+ Ecordova_Entry_Data *pd EINA_UNUSED,
+ Ecordova_Metadata *metadata EINA_UNUSED)
+{
+ ERR("Not implemented.");
+}
+
+static void
+_ecordova_entry_move(Eo *obj EINA_UNUSED,
+ Ecordova_Entry_Data *pd,
+ Ecordova_DirectoryEntry *parent,
+ const char *new_name)
+{
+ DBG("(%p)", obj);
+ EINA_SAFETY_ON_NULL_RETURN(parent);
+ if (!new_name) new_name = pd->name;
+
+ Eio_Operation_Data *data = _data_new(pd, _move_notify, _error_notify);
+
+ Ecordova_Entry_Data *dest_dir = eo_data_scope_get(parent, ECORDOVA_ENTRY_CLASS);
+
+ data->name = strdup(new_name);
+ data->path = strdup(dest_dir->native);
+
+ // TODO: file_system?
+
+ size_t len = strlen(data->path) + 1 + strlen(data->name) + 1;
+ data->native = malloc(len);
+ EINA_SAFETY_ON_NULL_GOTO(data->native, on_error);
+ snprintf(data->native, len, "%s/%s", data->path, new_name);
+
+ if (pd->is_file)
+ {
+ DBG("Moving file from %s to %s", pd->native, data->native);
+ data->file = eio_file_move(pd->native,
+ data->native,
+ _eio_progress_cb,
+ _eio_moved_cb,
+ _eio_error_cb,
+ data);
+ }
+ else
+ {
+ DBG("Moving directory from %s to %s", pd->native, data->native);
+ data->file = eio_dir_move(pd->native,
+ data->native,
+ _eio_filter_cb,
+ _eio_progress_cb,
+ _eio_moved_cb,
+ _eio_error_cb,
+ data);
+ }
+
+ pd->pending = eina_list_append(pd->pending, data);
+ return;
+
+on_error:
+ _data_free(data);
+}
+
+static void
+_ecordova_entry_copy(Eo *obj EINA_UNUSED,
+ Ecordova_Entry_Data *pd,
+ Ecordova_DirectoryEntry *parent,
+ const char *new_name)
+{
+ DBG("(%p)", obj);
+ EINA_SAFETY_ON_NULL_RETURN(parent);
+ if (!new_name) new_name = pd->name;
+
+ Eio_Operation_Data *data = _data_new(pd, _copy_notify, _error_notify);
+
+ Ecordova_Entry_Data *dest_dir = eo_data_scope_get(parent, ECORDOVA_ENTRY_CLASS);
+
+ data->name = strdup(new_name);
+ data->path = strdup(dest_dir->native);
+
+ // TODO: file_system?
+
+ size_t len = strlen(data->path) + 1 + strlen(data->name) + 1;
+ data->native = malloc(len);
+ EINA_SAFETY_ON_NULL_GOTO(data->native, on_error);
+ snprintf(data->native, len, "%s/%s", data->path, new_name);
+
+ if (pd->is_file)
+ data->file = eio_file_copy(pd->native,
+ data->native,
+ _eio_progress_cb,
+ _eio_copied_cb,
+ _eio_error_cb,
+ data);
+ else
+ data->file = eio_dir_copy(pd->native,
+ data->native,
+ _eio_filter_cb,
+ _eio_progress_cb,
+ _eio_copied_cb,
+ _eio_error_cb,
+ data);
+
+ pd->pending = eina_list_append(pd->pending, data);
+ return;
+
+on_error:
+ _data_free(data);
+}
+
+static void
+_ecordova_entry_remove(Eo *obj EINA_UNUSED, Ecordova_Entry_Data *pd)
+{
+ DBG("(%p)", obj);
+ _entry_remove(pd, _remove_notify, _error_notify, false);
+}
+
+void
+_entry_remove(Ecordova_Entry_Data *pd,
+ Ecordova_Entry_Success_Callback success_cb,
+ Ecordova_Entry_Error_Callback error_cb,
+ bool recursively)
+{
+ DBG("(%p)", pd->obj);
+
+ Eio_Operation_Data *data = _data_new(pd, success_cb, error_cb);
+
+ // TODO: file_system?
+
+ if (pd->is_file)
+ data->file = eio_file_unlink(pd->native,
+ _eio_removed_cb,
+ _eio_error_cb,
+ data);
+ else
+ {
+ Eio_Filter_Direct_Cb filter_cb =
+ recursively ? _eio_filter_cb
+ : _eio_remove_non_recursively_filter_cb;
+
+ data->file = eio_dir_unlink(pd->native,
+ filter_cb,
+ _eio_progress_cb,
+ _eio_removed_cb,
+ _eio_error_cb,
+ data);
+ }
+
+ pd->pending = eina_list_append(pd->pending, data);
+}
+
+static void
+_ecordova_entry_parent_get(Eo *obj, Ecordova_Entry_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ Eio_Operation_Data *data = _data_new(pd, _parent_get_notify, _error_notify);
+
+ data->file = eio_file_direct_stat(pd->native,
+ _parent_get_cb,
+ _eio_error_cb,
+ data);
+
+ pd->pending = eina_list_append(pd->pending, data);
+ }
+
+static void
+_parent_get_cb(void *user_data,
+ Eio_File *handler EINA_UNUSED,
+ const Eina_Stat *stat EINA_UNUSED)
+{
+ Eio_Operation_Data *data = user_data;
+ data->success_cb(data->pd->obj, data->pd);
+ _data_free(data);
+}
+
+static void
+_parent_get_notify(Eo *obj, void *data)
+{
+ Ecordova_Entry_Data *pd = data;
+
+ char *name, *path, *url;
+ split_path(NULL, pd->path, &path, &name, &url);
+
+ Ecordova_DirectoryEntry *parent =
+ eo_add(ECORDOVA_DIRECTORYENTRY_CLASS,
+ NULL,
+ ecordova_directoryentry_constructor(name,
+ path,
+ NULL, // TODO: filesystem ?
+ url));
+ free(name);
+ free(path);
+ free(url);
+
+ eo_do(obj, eo_event_callback_call(ECORDOVA_ENTRY_EVENT_PARENT_GET, parent));
+ eo_unref(parent);
+}
+
+static Eina_Bool
+_ecordova_entry_file_is_get(Eo *obj EINA_UNUSED, Ecordova_Entry_Data *pd)
+{
+ return pd->is_file;
+}
+
+static Eina_Bool
+_ecordova_entry_directory_is_get(Eo *obj EINA_UNUSED, Ecordova_Entry_Data *pd)
+{
+ return pd->is_directory;
+}
+
+static const char *
+_ecordova_entry_name_get(Eo *obj EINA_UNUSED, Ecordova_Entry_Data *pd)
+{
+ return pd->name;
+}
+
+static const char *
+_ecordova_entry_path_get(Eo *obj EINA_UNUSED, Ecordova_Entry_Data *pd)
+{
+ return pd->path;
+}
+
+void
+_metadata_get(Ecordova_Entry_Data *pd,
+ Ecordova_Entry_Success_Callback success_cb,
+ Ecordova_Entry_Error_Callback error_cb)
+{
+ DBG("(%p)", pd->obj);
+
+ Eio_Operation_Data *data = _data_new(pd, success_cb, error_cb);
+
+ data->file = eio_file_direct_stat(pd->native,
+ _eio_stat_cb,
+ _eio_error_cb,
+ data);
+
+ pd->pending = eina_list_append(pd->pending, data);
+}
+
+static void
+_eio_stat_cb(void *user_data,
+ Eio_File *handler EINA_UNUSED,
+ const Eina_Stat *stat)
+{
+ Eio_Operation_Data *data = user_data;
+ Ecordova_Metadata metadata = {
+ .modification_date = (time_t)stat->mtime,
+ .size = stat->size
+ };
+
+ data->success_cb(data->pd->obj, &metadata);
+ _data_free(data);
+}
+
+static void
+_metadata_notify(Eo *obj, void *data)
+{
+ eo_do(obj, eo_event_callback_call(ECORDOVA_ENTRY_EVENT_METADATA_GET, data));
+}
+
+void
+_eio_error_cb(void *user_data,
+ Eio_File *handler EINA_UNUSED,
+ int error)
+{
+ Eio_Operation_Data *data = user_data;
+ DBG("(%p)", data->pd->obj);
+ data->error_cb(data->pd->obj, error);
+ _data_free(data);
+}
+
+void
+_eio_progress_cb(void *data EINA_UNUSED,
+ Eio_File *handler EINA_UNUSED,
+ const Eio_Progress *info EINA_UNUSED)
+{
+}
+
+static void
+_eio_moved_cb(void *user_data, Eio_File *handler EINA_UNUSED)
+{
+ Eio_Operation_Data *data = user_data;
+ free(data->pd->path);
+ free(data->pd->name);
+ free(data->pd->native);
+ data->pd->path = data->path;
+ data->pd->name = data->name;
+ data->pd->native = data->native;
+ data->path = NULL;
+ data->name = NULL;
+ data->native = NULL;
+
+ data->success_cb(data->pd->obj, data->pd->obj);
+ _data_free(data);
+}
+
+static void
+_move_notify(Eo *obj, void *data)
+{
+ eo_do(obj, eo_event_callback_call(ECORDOVA_ENTRY_EVENT_MOVE_SUCCESS, data));
+}
+
+static void
+_eio_copied_cb(void *user_data, Eio_File *handler EINA_UNUSED)
+{
+ Eio_Operation_Data *data = user_data;
+ Ecordova_Entry *entry = NULL;
+ if (data->pd->is_file)
+ entry = eo_add(ECORDOVA_FILEENTRY_CLASS,
+ NULL,
+ ecordova_fileentry_constructor(data->name,
+ data->path,
+ data->pd->file_system,
+ data->native));
+ else
+ entry = eo_add(ECORDOVA_DIRECTORYENTRY_CLASS,
+ NULL,
+ ecordova_directoryentry_constructor(data->name,
+ data->path,
+ data->pd->file_system,
+ data->native));
+
+ data->success_cb(data->pd->obj, entry);
+
+ eo_unref(entry);
+ _data_free(data);
+}
+
+static void
+_copy_notify(Eo *obj, void *data)
+{
+ eo_do(obj, eo_event_callback_call(ECORDOVA_ENTRY_EVENT_COPY_SUCCESS, data));
+}
+
+void
+_eio_removed_cb(void *user_data, Eio_File *handler EINA_UNUSED)
+{
+ Eio_Operation_Data *data = user_data;
+ data->success_cb(data->pd->obj, NULL);
+ _data_free(data);
+}
+
+static void
+_remove_notify(Eo *obj, void *data)
+{
+ eo_do(obj, eo_event_callback_call(ECORDOVA_ENTRY_EVENT_REMOVE_SUCCESS, data));
+}
+
+Eina_Bool
+_eio_filter_cb(void *data EINA_UNUSED,
+ Eio_File *handler EINA_UNUSED,
+ const Eina_File_Direct_Info *info EINA_UNUSED)
+{
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_eio_remove_non_recursively_filter_cb(void *user_data,
+ Eio_File *handler EINA_UNUSED,
+ const Eina_File_Direct_Info *info EINA_UNUSED)
+{
+ Eio_Operation_Data *data = user_data;
+ DBG("filter_cb: %s", info->path);
+ if (++data->count != 1)
+ {
+ eio_file_cancel(handler);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+Eio_Operation_Data *
+_data_new(Ecordova_Entry_Data *pd,
+ Ecordova_Entry_Success_Callback success_cb,
+ Ecordova_Entry_Error_Callback error_cb)
+{
+ Eio_Operation_Data *data = calloc(1, sizeof(Eio_Operation_Data));
+ data->pd = pd;
+ data->success_cb = success_cb;
+ data->error_cb = error_cb;
+ return data;
+}
+
+void
+_data_free(Eio_Operation_Data *data)
+{
+ EINA_SAFETY_ON_NULL_RETURN(data);
+
+ data->pd->pending = eina_list_remove(data->pd->pending, data);
+ free(data->path);
+ free(data->name);
+ free(data->native);
+ free(data);
+}
+
+void
+_error_notify(Eo *obj, int error)
+{
+ Ecordova_FileError file_error = _translate_errno(error);
+ eo_do(obj, eo_event_callback_call(ECORDOVA_ENTRY_EVENT_ERROR, &file_error));
+}
+
+Ecordova_FileError
+_translate_errno(int error)
+{
+ // TODO: translate other errors
+ switch (error)
+ {
+ case EPERM:
+ case EACCES:
+ return ECORDOVA_FILEERROR_SECURITY_ERR;
+ case ENOENT:
+ return ECORDOVA_FILEERROR_NOT_FOUND_ERR;
+ }
+
+ return -1;
+}
+
+#include "ecordova_entry.eo.c"
diff --git a/src/lib/ecordova/ecordova_entry.eo b/src/lib/ecordova/ecordova_entry.eo
new file mode 100644
index 0000000000..044c9231a5
--- /dev/null
+++ b/src/lib/ecordova/ecordova_entry.eo
@@ -0,0 +1,114 @@
+struct Ecordova_Metadata {
+ modification_date: time;
+ size: long;
+}
+
+class Ecordova.Entry (Eo.Base) {
+ [[Represents a file or directory on the local file system.]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_Entry constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ params {
+ file_is: bool;
+ [[true if Entry is a file]]
+
+ directory_is: bool;
+ [[true if Entry is a directory]]
+
+ name: const(char)*;
+ [[name of the file or directory, excluding the path leading to it]]
+
+ path: const(char)*;
+ [[the absolute full path to the file or directory]]
+
+ file_system: Ecordova.FileSystem*;
+ [[the filesystem on which this entry resides]]
+
+ url: const(char)*;
+ [[an alternate URL which can be used by native webview controls,
+ for example media players.]]
+ }
+ }
+ metadata_get {
+ [[Look up the metadata of the entry.]]
+ }
+ metadata_set {
+ [[Set the metadata of the entry.]]
+ params {
+ metadata: Ecordova_Metadata*; [[keys and values to set]]
+ }
+ }
+ move {
+ [[Move a file or directory to a new location.]]
+ params {
+ parent: Eo*/*Ecordova.DirectoryEntry*/;
+ [[the directory to which to move this entry]]
+
+ new_name: const(char)*;
+ [[new name of the entry, defaults to the current name]]
+ }
+ }
+ copy {
+ [[Copy a directory to a different location.]]
+ params {
+ parent: Eo*/*Ecordova.DirectoryEntry*/;
+ [[the directory to which to copy this entry]]
+
+ new_name: const(char)*;
+ [[new name of the entry, defaults to the current name]]
+ }
+ }
+ remove {
+ [[Remove a file or directory. It is an error to attempt to delete
+ a directory that is not empty. It is an error to attempt to
+ delete a root directory of a file system.]]
+ }
+ parent_get {
+ [[Look up the parent DirectoryEntry of this entry.]]
+ }
+ @property file_is {
+ get {}
+ values {
+ value: bool;
+ }
+ }
+ @property directory_is {
+ get {}
+ values {
+ value: bool;
+ }
+ }
+ @property name {
+ get {}
+ values {
+ value: const(char)*;
+ }
+ }
+ @property path {
+ get {}
+ values {
+ value: const(char)*;
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ metadata,get: const(Ecordova_Metadata)*;
+ error: Ecordova_FileError*;
+ move,success: const(Ecordova.Entry)*;
+ copy,success: const(Ecordova.Entry)*;
+ remove,success;
+ parent,get: const(Eo)/*Ecordova.DirectoryEntry*/*;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_entry_private.h b/src/lib/ecordova/ecordova_entry_private.h
new file mode 100644
index 0000000000..5bcf00aac4
--- /dev/null
+++ b/src/lib/ecordova/ecordova_entry_private.h
@@ -0,0 +1,53 @@
+#ifndef _ECORDOVA_ENTRY_PRIVATE_H
+#define _ECORDOVA_ENTRY_PRIVATE_H
+
+#include "ecordova_private.h"
+
+#include <Eio.h>
+
+#include <stdbool.h>
+
+typedef struct _Ecordova_Entry_Data Ecordova_Entry_Data;
+
+/**
+ * Ecordova.Entry private data
+ */
+struct _Ecordova_Entry_Data
+{
+ Eo *obj;
+ Eina_Bool is_file;
+ Eina_Bool is_directory;
+ char *name;
+ char *path;
+ Ecordova_FileSystem *file_system;
+ char *native;
+ Eina_List *pending;
+};
+
+typedef void(*Ecordova_Entry_Success_Callback)(Eo *, void *);
+typedef void(*Ecordova_Entry_Error_Callback)(Eo *, int);
+
+typedef struct
+{
+ Ecordova_Entry_Data *pd;
+ Eio_File *file;
+ char *path;
+ char *name;
+ char *native;
+ Ecordova_Entry_Success_Callback success_cb;
+ Ecordova_Entry_Error_Callback error_cb;
+ unsigned long count;
+} Eio_Operation_Data;
+
+Eio_Operation_Data *_data_new(Ecordova_Entry_Data *, Ecordova_Entry_Success_Callback, Ecordova_Entry_Error_Callback);
+void _data_free(Eio_Operation_Data *);
+void _metadata_get(Ecordova_Entry_Data *, Ecordova_Entry_Success_Callback, Ecordova_Entry_Error_Callback);
+void _entry_remove(Ecordova_Entry_Data *, Ecordova_Entry_Success_Callback, Ecordova_Entry_Error_Callback, bool);
+void _error_notify(Eo *, int);
+void _eio_error_cb(void *, Eio_File *, int);
+void _eio_removed_cb(void *, Eio_File *);
+Eina_Bool _eio_filter_cb(void *, Eio_File *, const Eina_File_Direct_Info *);
+void _eio_progress_cb(void *, Eio_File *, const Eio_Progress *);
+Ecordova_FileError _translate_errno(int);
+
+#endif
diff --git a/src/lib/ecordova/ecordova_file.c b/src/lib/ecordova/ecordova_file.c
new file mode 100644
index 0000000000..69f5a61eb2
--- /dev/null
+++ b/src/lib/ecordova/ecordova_file.c
@@ -0,0 +1,128 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_file_private.h"
+
+#define MY_CLASS ECORDOVA_FILE_CLASS
+#define MY_CLASS_NAME "Ecordova_File"
+
+static Eo_Base *
+_ecordova_file_eo_base_constructor(Eo *obj, Ecordova_File_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_file_constructor(Eo *obj,
+ Ecordova_File_Data *pd,
+ const char *name,
+ const char *url,
+ const char *type,
+ time_t last_modified_date,
+ long size)
+{
+ DBG("(%p)", obj);
+ pd->name = name ? strdup(name) : strdup("");
+ pd->url = url ? strdup(url) : NULL;
+ pd->type = type ? strdup(type) : NULL;
+ pd->modified_date = last_modified_date;
+ pd->size = size;
+
+ pd->start = 0;
+ pd->end = pd->size;
+}
+
+static void
+_ecordova_file_eo_base_destructor(Eo *obj, Ecordova_File_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ free(pd->name);
+ free(pd->url);
+ free(pd->type);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static Ecordova_File *
+_ecordova_file_slice(Eo *obj EINA_UNUSED,
+ Ecordova_File_Data *pd,
+ long start,
+ long end)
+{
+ DBG("(%p) start=%ld end=%ld", obj, start, end);
+ long size = pd->end - pd->start;
+ long new_start = 0;
+ long new_end = size;
+
+ if (start < 0)
+ new_start = MAX(size + start, 0);
+ else
+ new_start = MIN(size, start);
+
+ if (end < 0)
+ new_end = MAX(size + end, 0);
+ else
+ new_end = MIN(end, size);
+
+ if (new_start > new_end)
+ {
+ long aux = new_start;
+ new_start = new_end;
+ new_end = aux;
+ }
+
+ Ecordova_File *new_file = eo_add(MY_CLASS, NULL,
+ ecordova_file_constructor(pd->name,
+ pd->url,
+ pd->type,
+ pd->modified_date,
+ pd->size));
+ EINA_SAFETY_ON_NULL_RETURN_VAL(new_file, NULL);
+
+ Ecordova_File_Data *new_file_pd = eo_data_scope_get(new_file, MY_CLASS);
+ EINA_SAFETY_ON_NULL_GOTO(new_file_pd, on_error);
+
+ new_file_pd->start = pd->start + new_start;
+ new_file_pd->end = pd->start + new_end;
+ return new_file;
+
+on_error:
+ eo_unref(new_file);
+ return NULL;
+}
+
+static const char *
+_ecordova_file_name_get(Eo *obj EINA_UNUSED, Ecordova_File_Data *pd)
+{
+ DBG("(%p)", obj);
+ return pd->name;
+}
+
+static const char *
+_ecordova_file_url_get(Eo *obj EINA_UNUSED, Ecordova_File_Data *pd)
+{
+ DBG("(%p)", obj);
+ return pd->url;
+}
+
+static long
+_ecordova_file_start_get(Eo *obj EINA_UNUSED, Ecordova_File_Data *pd)
+{
+ DBG("(%p)", obj);
+ return pd->start;
+}
+
+static long
+_ecordova_file_end_get(Eo *obj EINA_UNUSED, Ecordova_File_Data *pd)
+{
+ DBG("(%p)", obj);
+ return pd->end;
+}
+
+#include "ecordova_file.eo.c"
diff --git a/src/lib/ecordova/ecordova_file.eo b/src/lib/ecordova/ecordova_file.eo
new file mode 100644
index 0000000000..68eb529b5b
--- /dev/null
+++ b/src/lib/ecordova/ecordova_file.eo
@@ -0,0 +1,61 @@
+class Ecordova.File (Eo.Base) {
+ [[Ecordova File Plugin
+ Plugin ID: org.apache.cordova.file
+ http://plugins.cordova.io/#/package/org.apache.cordova.file
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_File constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ params {
+ name: const(char)*; [[name of the file, without path information]]
+ url: const(char)*; [[the full path of the file, including the name]]
+ type: const(char)*; [[mime type]]
+ last_modified_date: time; [[last modified date]]
+ size: long; [[size of the file in bytes]]
+ }
+ }
+ slice {
+ params {
+ start: long;
+ end: long;
+ }
+ return: own(Ecordova.File*);
+ }
+ @property name {
+ get {}
+ values {
+ value: const(char)*;
+ }
+ }
+ @property url {
+ get {}
+ values {
+ value: const(char)*;
+ }
+ }
+ @property start {
+ get {}
+ values {
+ value: long;
+ }
+ }
+ @property end {
+ get {}
+ values {
+ value: long;
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_file_private.h b/src/lib/ecordova/ecordova_file_private.h
new file mode 100644
index 0000000000..9e17c1805b
--- /dev/null
+++ b/src/lib/ecordova/ecordova_file_private.h
@@ -0,0 +1,23 @@
+#ifndef _ECORDOVA_FILE_PRIVATE_H
+#define _ECORDOVA_FILE_PRIVATE_H
+
+#include "ecordova_private.h"
+
+typedef struct _Ecordova_File_Data Ecordova_File_Data;
+
+/**
+ * Ecordova.File private data
+ */
+struct _Ecordova_File_Data
+{
+ Eo *obj;
+ char *name;
+ char *url;
+ char *type;
+ time_t modified_date;
+ long size;
+ long start;
+ long end;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_fileentry.c b/src/lib/ecordova/ecordova_fileentry.c
new file mode 100644
index 0000000000..337be04c7d
--- /dev/null
+++ b/src/lib/ecordova/ecordova_fileentry.c
@@ -0,0 +1,109 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_fileentry_private.h"
+#include "ecordova_entry_private.h"
+
+#define MY_CLASS ECORDOVA_FILEENTRY_CLASS
+#define MY_CLASS_NAME "Ecordova_FileEntry"
+
+static void _file_notify(Eo *, void *);
+static void _writer_create(Eo *, void *);
+
+static Eo_Base *
+_ecordova_fileentry_eo_base_constructor(Eo *obj, Ecordova_FileEntry_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_fileentry_constructor(Eo *obj,
+ Ecordova_FileEntry_Data *pd EINA_UNUSED,
+ const char *name,
+ const char *path,
+ Ecordova_FileSystem *file_system,
+ const char *url)
+{
+ DBG("(%p)", obj);
+ eo_do_super(obj, MY_CLASS, ecordova_entry_constructor(EINA_TRUE,
+ EINA_FALSE,
+ name,
+ path,
+ file_system,
+ url));
+}
+
+static void
+_ecordova_fileentry_eo_base_destructor(Eo *obj,
+ Ecordova_FileEntry_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_fileentry_writer_create(Eo *obj,
+ Ecordova_FileEntry_Data *pd EINA_UNUSED)
+{
+ Ecordova_Entry_Data *super = eo_data_scope_get(obj, ECORDOVA_ENTRY_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN(super);
+
+ _metadata_get(super, _writer_create, _error_notify);
+}
+
+static void
+_ecordova_fileentry_file(Eo *obj, Ecordova_FileEntry_Data *pd EINA_UNUSED)
+{
+ Ecordova_Entry_Data *super = eo_data_scope_get(obj, ECORDOVA_ENTRY_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN(super);
+
+ _metadata_get(super, _file_notify, _error_notify);
+}
+
+static Ecordova_File *
+_create_file(Eo *obj, const Ecordova_Metadata *metadata)
+{
+ Ecordova_Entry_Data *super = eo_data_scope_get(obj, ECORDOVA_ENTRY_CLASS);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(super, NULL);
+
+ return eo_add(ECORDOVA_FILE_CLASS, NULL,
+ ecordova_file_constructor(super->name,
+ super->native,
+ NULL, //< TODO: mime-type?
+ metadata->modification_date,
+ metadata->size));
+}
+
+static void
+_file_notify(Eo *obj, void *data)
+{
+ const Ecordova_Metadata *metadata = data;
+
+ Ecordova_File *file = _create_file(obj, metadata);
+
+ eo_do(obj, eo_event_callback_call(ECORDOVA_FILEENTRY_EVENT_FILE, file));
+ eo_unref(file);
+}
+
+static void
+_writer_create(Eo *obj, void *data)
+{
+ const Ecordova_Metadata *metadata = data;
+ Ecordova_File *file = _create_file(obj, metadata);
+ Ecordova_FileWriter *writer = eo_add(ECORDOVA_FILEWRITER_CLASS, NULL,
+ ecordova_filewriter_constructor(file));
+
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_FILEENTRY_EVENT_CREATE_WRITER, writer));
+
+ eo_unref(writer);
+ eo_unref(file);
+}
+
+#include "ecordova_fileentry.eo.c"
diff --git a/src/lib/ecordova/ecordova_fileentry.eo b/src/lib/ecordova/ecordova_fileentry.eo
new file mode 100644
index 0000000000..c635c8e942
--- /dev/null
+++ b/src/lib/ecordova/ecordova_fileentry.eo
@@ -0,0 +1,48 @@
+class Ecordova.FileEntry (Ecordova.Entry) {
+ [[An interface representing a file on the file system.]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_FileEntry constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ params {
+ name: const(char)*;
+ [[name of the file, excluding the path leading to it]]
+
+ path: const(char)*;
+ [[the absolute full path to the file]]
+
+ file_system: Ecordova.FileSystem*;
+ [[filesystem on which the file resides]]
+
+ url: const(char)*;
+ [[an alternate URL which can be used by native webview
+ controls, for example media players.]]
+ }
+ }
+ writer_create {
+ [[Creates a new FileWriter associated with the file that this
+ FileEntry represents.]]
+ }
+ file {
+ [[Returns a File that represents the current state of the file
+ that this FileEntry represents.]]
+ }
+
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ create,writer: Ecordova.FileWriter*;
+ file: Ecordova.File*;
+ error: Ecordova_FileError*;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_fileentry_private.h b/src/lib/ecordova/ecordova_fileentry_private.h
new file mode 100644
index 0000000000..832aeb881c
--- /dev/null
+++ b/src/lib/ecordova/ecordova_fileentry_private.h
@@ -0,0 +1,16 @@
+#ifndef _ECORDOVA_FILEENTRY_PRIVATE_H
+#define _ECORDOVA_FILEENTRY_PRIVATE_H
+
+#include "ecordova_private.h"
+
+typedef struct _Ecordova_FileEntry_Data Ecordova_FileEntry_Data;
+
+/**
+ * Ecordova.FileEntry private data
+ */
+struct _Ecordova_FileEntry_Data
+{
+ Eo *obj;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_filereader.c b/src/lib/ecordova/ecordova_filereader.c
new file mode 100644
index 0000000000..e90bde02d5
--- /dev/null
+++ b/src/lib/ecordova/ecordova_filereader.c
@@ -0,0 +1,272 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_filereader_private.h"
+#include "ecordova_entry_private.h"
+
+#include <Eio.h>
+
+#define MY_CLASS ECORDOVA_FILEREADER_CLASS
+#define MY_CLASS_NAME "Ecordova_FileReader"
+
+static void _read_cb(void *, Ecore_Thread *);
+static void _progress_notify(size_t, size_t, Eo *, Ecore_Thread *);
+static void _read_progress_cb(void *, Ecore_Thread *, void *);
+static void _read_end_cb(void *, Ecore_Thread *);
+static void _read_abort_cb(void *, Ecore_Thread *);
+
+static Eo_Base *
+_ecordova_filereader_eo_base_constructor(Eo *obj, Ecordova_FileReader_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->error = 0;
+ pd->state = ECORDOVA_FILEREADER_STATE_EMPTY;
+ pd->result = NULL;
+ pd->result_length = 0;
+ pd->thread = NULL;
+ pd->url = NULL;
+ pd->offset = 0;
+ pd->length = 0;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_filereader_constructor(Eo *obj EINA_UNUSED,
+ Ecordova_FileReader_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+}
+
+static void
+_ecordova_filereader_eo_base_destructor(Eo *obj, Ecordova_FileReader_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ if (pd->thread) ERR("%s", "Destructing without aborting first");
+
+ free(pd->result);
+ free(pd->url);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_filereader_abort(Eo *obj, Ecordova_FileReader_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ if (ECORDOVA_FILEREADER_STATE_DONE == pd->state ||
+ ECORDOVA_FILEREADER_STATE_EMPTY == pd->state)
+ return;
+ pd->error = ECORDOVA_FILEERROR_ABORT_ERR;
+ pd->state = ECORDOVA_FILEREADER_STATE_DONE;
+
+ if (pd->thread)
+ ecore_thread_cancel(pd->thread);
+}
+
+static Ecordova_FileError
+_ecordova_filereader_read(Eo *obj,
+ Ecordova_FileReader_Data *pd,
+ Ecordova_File *file)
+{
+ DBG("(%p)", obj);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(file, ECORDOVA_FILEERROR_SYNTAX_ERR);
+
+ if (ECORDOVA_FILEREADER_STATE_LOADING == pd->state)
+ return ECORDOVA_FILEERROR_INVALID_STATE_ERR;
+ pd->state = ECORDOVA_FILEREADER_STATE_LOADING;
+ pd->error = 0;
+
+ const char *url;
+ eo_do(file,
+ url = ecordova_file_url_get(),
+ pd->offset = ecordova_file_start_get(),
+ pd->length = ecordova_file_end_get() - pd->offset);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(url, ECORDOVA_FILEERROR_SYNTAX_ERR);
+ pd->url = strdup(url);
+
+ Ecordova_ProgressEvent loadstart = {.type = "loadstart", .target = obj};
+ eo_do(obj, eo_event_callback_call(ECORDOVA_FILEREADER_EVENT_ON_LOAD_START, &loadstart));
+
+ pd->thread = ecore_thread_feedback_run(_read_cb,
+ _read_progress_cb,
+ _read_end_cb,
+ _read_abort_cb,
+ pd,
+ EINA_FALSE);
+ return 0;
+}
+
+static Ecordova_FileError
+_ecordova_filereader_error_get(Eo *obj, Ecordova_FileReader_Data *pd)
+{
+ DBG("(%p)", obj);
+ return pd->error;
+}
+
+static const char *
+_ecordova_filereader_result_get(Eo *obj, Ecordova_FileReader_Data *pd)
+{
+ DBG("(%p)", obj);
+ return pd->result;
+}
+
+static size_t
+_ecordova_filereader_length_get(Eo *obj, Ecordova_FileReader_Data *pd)
+{
+ DBG("(%p)", obj);
+ return pd->result_length;
+}
+
+static Ecordova_FileReader_State
+_ecordova_filereader_state_get(Eo *obj, Ecordova_FileReader_Data *pd)
+{
+ DBG("(%p)", obj);
+ return pd->state;
+}
+
+static void
+_read_cb(void *data, Ecore_Thread *thread)
+{
+ Ecordova_FileReader_Data *pd = data;
+ DBG("(%p)", pd->obj);
+
+ if (ecore_thread_check(thread))
+ return;
+
+ FILE *stream = fopen(pd->url, "rb");
+ if (!stream)
+ {
+ pd->error = _translate_errno(errno);
+ return;
+ }
+
+ if (pd->offset > 0)
+ {
+ int error = fseek(stream, pd->offset, SEEK_SET);
+ if (error)
+ {
+ pd->error = _translate_errno(errno);
+ goto on_error;
+ }
+ }
+
+ _progress_notify(0, pd->length, pd->obj, thread);
+ if (ecore_thread_check(thread))
+ goto on_error;
+
+ pd->result = pd->result ? realloc(pd->result, pd->length * sizeof(char))
+ : malloc(pd->length * sizeof(char));
+ if (NULL == pd->result)
+ {
+ pd->error = _translate_errno(errno);
+ goto on_error;
+ }
+
+ pd->result_length = 0;
+ size_t total = pd->length;
+ char *buffer = pd->result;
+ do
+ {
+ size_t read = fread(buffer, sizeof(char), total, stream);
+ if (!read)
+ {
+ pd->error = _translate_errno(errno);
+ goto on_error;
+ }
+
+ buffer += read;
+ total -= read;
+ pd->result_length += read;
+
+ _progress_notify(pd->length - total, pd->length, pd->obj, thread);
+ if (ecore_thread_check(thread))
+ goto on_error;
+ }
+ while (total > 0);
+
+on_error:
+ fclose(stream);
+}
+
+static void
+_progress_notify(size_t read, size_t total, Eo *obj, Ecore_Thread *thread)
+{
+ DBG("(%p)", obj);
+ Ecordova_ProgressEvent *progress = malloc(sizeof(Ecordova_ProgressEvent));
+ *progress = (Ecordova_ProgressEvent)
+ {
+ .type = "progress",
+ .length_computable = EINA_TRUE,
+ .loaded = read,
+ .total = total,
+ .target = obj
+ };
+ if (!ecore_thread_feedback(thread, progress))
+ free(progress);
+}
+
+static void
+_read_progress_cb(void *data,
+ Ecore_Thread *thread EINA_UNUSED,
+ void *msg_data)
+{
+ Ecordova_FileReader_Data *pd = data;
+ DBG("(%p)", pd->obj);
+ Ecordova_ProgressEvent *event = msg_data;
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILEREADER_EVENT_ON_PROGRESS, &event));
+ free(event);
+}
+
+static void
+_read_end_cb(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+ Ecordova_FileReader_Data *pd = data;
+ DBG("(%p)", pd->obj);
+
+ // If DONE (cancelled), then don't do anything
+ if (ECORDOVA_FILEREADER_STATE_DONE == pd->state)
+ return;
+ pd->thread = NULL;
+ pd->state = ECORDOVA_FILEREADER_STATE_DONE;
+
+ if (pd->error)
+ {
+ Ecordova_ProgressEvent error = {.type = "error", .target = pd->obj};
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILEREADER_EVENT_ON_ERROR, &error));
+ }
+ else
+ {
+ Ecordova_ProgressEvent load = {.type = "load", .target = pd->obj};
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILEREADER_EVENT_ON_LOAD, &load));
+ }
+
+ Ecordova_ProgressEvent loadend = {.type = "loadend", .target = pd->obj};
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILEREADER_EVENT_ON_LOAD_END, &loadend));
+}
+
+static void
+_read_abort_cb(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+ Ecordova_FileReader_Data *pd = data;
+ DBG("(%p)", pd->obj);
+
+ pd->thread = NULL;
+
+ Ecordova_ProgressEvent on_abort = {.type = "abort", .target = pd->obj};
+ eo_do(pd->obj, eo_event_callback_call(ECORDOVA_FILEREADER_EVENT_ON_ABORT, &on_abort));
+
+ Ecordova_ProgressEvent loadend = {.type = "loadend", .target = pd->obj};
+ eo_do(pd->obj, eo_event_callback_call(ECORDOVA_FILEREADER_EVENT_ON_LOAD_END, &loadend));
+}
+
+#include "ecordova_filereader.eo.c"
diff --git a/src/lib/ecordova/ecordova_filereader.eo b/src/lib/ecordova/ecordova_filereader.eo
new file mode 100644
index 0000000000..4dcdd7a759
--- /dev/null
+++ b/src/lib/ecordova/ecordova_filereader.eo
@@ -0,0 +1,92 @@
+enum Ecordova_FileReader_State {
+ EMPTY = 0,
+ LOADING = 1,
+ DONE = 2
+}
+
+struct Ecordova_ProgressEvent {
+ type: const(char)*;
+ bubbles: bool;
+ cancel_bubble: bool;
+ cancelable: bool;
+ length_computable: bool;
+ loaded: int;
+ total: int;
+ target: Eo*;
+}
+
+class Ecordova.FileReader (Eo.Base) {
+ [[This class reads the device file system.]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_FileReader constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ }
+ abort {
+ [[Abort reading file.]]
+ }
+ read {
+ [[Read file and return data as a binary data.]]
+ params {
+ file: Ecordova.File*; [[File object containing file properties]]
+ }
+ return: Ecordova_FileError;
+ }
+ @property error {
+ get {}
+ values {
+ value: Ecordova_FileError;
+ }
+ }
+ @property result {
+ get {}
+ values {
+ value: const(char)*;
+ }
+ }
+ @property length {
+ get {}
+ values {
+ value: size;
+ }
+ }
+ @property state {
+ get {}
+ values {
+ state: Ecordova_FileReader_State;
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ on,load,start: const(Ecordova_ProgressEvent)*;
+ [[When read starts]]
+
+ on,progress: const(Ecordova_ProgressEvent)*;
+ [[While reading (and decoding) file or fileBlob data, and reporting
+ partial file data (progress.loaded/progress.total)]]
+
+ on,load: const(Ecordova_ProgressEvent)*;
+ [[When the read has successfully completed.]]
+
+ on,error: const(Ecordova_ProgressEvent)*;
+ [[When the read has failed (see errors).]]
+
+ on,load,end: const(Ecordova_ProgressEvent)*;
+ [[When the request has completed (either in success or failure).]]
+
+ on,abort: const(Ecordova_ProgressEvent)*;
+ [[When the read has been aborted. For instance, by invoking the
+ abort() method.]]
+ }
+}
diff --git a/src/lib/ecordova/ecordova_filereader_private.h b/src/lib/ecordova/ecordova_filereader_private.h
new file mode 100644
index 0000000000..bff6857eca
--- /dev/null
+++ b/src/lib/ecordova/ecordova_filereader_private.h
@@ -0,0 +1,26 @@
+#ifndef _ECORDOVA_FILEREADER_PRIVATE_H
+#define _ECORDOVA_FILEREADER_PRIVATE_H
+
+#include "ecordova_private.h"
+
+#include <Eio.h>
+
+typedef struct _Ecordova_FileReader_Data Ecordova_FileReader_Data;
+
+/**
+ * Ecordova.FileReader private data
+ */
+struct _Ecordova_FileReader_Data
+{
+ Eo *obj;
+ Ecordova_FileError error;
+ Ecordova_FileReader_State state;
+ char *result;
+ size_t result_length;
+ Ecore_Thread *thread;
+ char *url;
+ long offset;
+ long length;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_filesystem.c b/src/lib/ecordova/ecordova_filesystem.c
new file mode 100644
index 0000000000..4086a84b68
--- /dev/null
+++ b/src/lib/ecordova/ecordova_filesystem.c
@@ -0,0 +1,38 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_filesystem_private.h"
+
+#define MY_CLASS ECORDOVA_FILESYSTEM_CLASS
+#define MY_CLASS_NAME "Ecordova_FileSystem"
+
+static Eo_Base *
+_ecordova_filesystem_eo_base_constructor(Eo *obj, Ecordova_FileSystem_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_filesystem_constructor(Eo *obj EINA_UNUSED,
+ Ecordova_FileSystem_Data *pd EINA_UNUSED,
+ const char *name EINA_UNUSED,
+ Ecordova_DirectoryEntry *root EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+}
+
+static void
+_ecordova_filesystem_eo_base_destructor(Eo *obj,
+ Ecordova_FileSystem_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+#include "ecordova_filesystem.eo.c"
diff --git a/src/lib/ecordova/ecordova_filesystem.eo b/src/lib/ecordova/ecordova_filesystem.eo
new file mode 100644
index 0000000000..fb201034c7
--- /dev/null
+++ b/src/lib/ecordova/ecordova_filesystem.eo
@@ -0,0 +1,25 @@
+class Ecordova.FileSystem (Eo.Base) {
+ [[An interface representing a file system]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_FileSystem constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ params {
+ name: const(char)*; [[name the unique name of the file system]]
+ root: Eo*/*Ecordova.DirectoryEntry*/; [[root directory of the file system]]
+ }
+ }
+
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_filesystem_private.h b/src/lib/ecordova/ecordova_filesystem_private.h
new file mode 100644
index 0000000000..ef5756bdb3
--- /dev/null
+++ b/src/lib/ecordova/ecordova_filesystem_private.h
@@ -0,0 +1,16 @@
+#ifndef _ECORDOVA_FILESYSTEM_PRIVATE_H
+#define _ECORDOVA_FILESYSTEM_PRIVATE_H
+
+#include "ecordova_private.h"
+
+typedef struct _Ecordova_FileSystem_Data Ecordova_FileSystem_Data;
+
+/**
+ * Ecordova.FileSystem private data
+ */
+struct _Ecordova_FileSystem_Data
+{
+ Eo *obj;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_filetransfer.c b/src/lib/ecordova/ecordova_filetransfer.c
new file mode 100644
index 0000000000..c0643e81f7
--- /dev/null
+++ b/src/lib/ecordova/ecordova_filetransfer.c
@@ -0,0 +1,613 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_filetransfer_private.h"
+#include "ecordova_directoryentry_private.h"
+
+#include <Ecore_Con.h>
+
+#define MY_CLASS ECORDOVA_FILETRANSFER_CLASS
+#define MY_CLASS_NAME "Ecordova_FileTransfer"
+
+struct _Ecordova_FileTransfer_Job
+{
+ char *source;
+ char *target;
+ Ecore_File_Download_Job *download;
+ Ecore_Thread *upload;
+ int upload_error;
+ char *upload_buffer;
+ long int upload_length;
+ Ecore_Con_Url *upload_con_url;
+ Ecore_Event_Handler *progress_event_hanbler;
+ Ecore_Event_Handler *complete_event_hanbler;
+ Ecordova_FileTransfer_UploadOptions upload_options;
+};
+
+static int _download_progress_cb(void *, const char *, long int, long int, long int, long int);
+static void _download_completion_cb(void *, const char *, int);
+static void _clear(Ecordova_FileTransfer_Data *);
+static void _abort_error_notify(Ecordova_FileTransfer_Data *);
+static void _status_error_notify(Ecordova_FileTransfer_Data *, int);
+static void _file_error_notify(Ecordova_FileTransfer_Data *, int);
+static void _connection_error_notify(Ecordova_FileTransfer_Data *);
+static void _already_in_progress_error_notify(Ecordova_FileTransfer_Data *, const char *, const char *);
+static void _upload_cb(void *, Ecore_Thread *);
+static void _upload_progress_notify(size_t, size_t, Eo *, Ecore_Thread *);
+static void _upload_progress_cb(void *, Ecore_Thread *, void *);
+static void _upload_end_cb(void *, Ecore_Thread *);
+static void _upload_abort_cb(void *, Ecore_Thread *);
+static void _progress_notify(Ecordova_FileTransfer_Data *, Ecordova_ProgressEvent *);
+static Ecordova_FileTransfer_Job *_job_new(const char *, const char *);
+static void _job_free(Ecordova_FileTransfer_Job **);
+static Eina_Bool _url_progress_cb(void *, int, void *);
+static Eina_Bool _url_complete_cb(void *, int, void *);
+
+static Eo_Base *
+_ecordova_filetransfer_eo_base_constructor(Eo *obj,
+ Ecordova_FileTransfer_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->job = NULL;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_filetransfer_constructor(Eo *obj EINA_UNUSED,
+ Ecordova_FileTransfer_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+}
+
+static void
+_ecordova_filetransfer_eo_base_destructor(Eo *obj,
+ Ecordova_FileTransfer_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ _clear(pd);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_filetransfer_upload(Eo *obj EINA_UNUSED,
+ Ecordova_FileTransfer_Data *pd EINA_UNUSED,
+ const char *file_url EINA_UNUSED,
+ const char *server,
+ Ecordova_FileTransfer_UploadOptions *options EINA_UNUSED,
+ Eina_Bool trust_all_hosts EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+ EINA_SAFETY_ON_NULL_RETURN(file_url);
+ EINA_SAFETY_ON_NULL_RETURN(server);
+
+ if (pd->job)
+ {
+ _already_in_progress_error_notify(pd, file_url, server);
+ return;
+ }
+
+ bool is_http = strncmp(server, "http://", 7) == 0;
+ bool is_https = strncmp(server, "https://", 8) == 0;
+
+ if (!is_http && !is_https)
+ {
+ ERR("%s", "Invalid server address");
+ Ecordova_FileTransfer_Error error = {
+ .code = ECORDOVA_FILETRANSFER_ERRORCODE_INVALID_URL_ERR,
+ .source = file_url,
+ .target = server,
+ .http_status = 0,
+ .body = NULL,
+ .exception = "Invalid server address"
+ };
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_ERROR, &error));
+ return;
+ }
+
+ pd->job = _job_new(file_url, server);
+ pd->job->upload = ecore_thread_feedback_run(_upload_cb,
+ _upload_progress_cb,
+ _upload_end_cb,
+ _upload_abort_cb,
+ pd,
+ EINA_FALSE);
+}
+
+static void
+_ecordova_filetransfer_download(Eo *obj,
+ Ecordova_FileTransfer_Data *pd,
+ const char *source,
+ const char *target,
+ Eina_Bool trust_all_hosts EINA_UNUSED,
+ Eina_Hash *options)
+{
+ DBG("(%p)", obj);
+ EINA_SAFETY_ON_NULL_RETURN(source);
+ EINA_SAFETY_ON_NULL_RETURN(target);
+
+ if (pd->job)
+ {
+ _already_in_progress_error_notify(pd, source, target);
+ return;
+ }
+
+ Ecordova_FileTransfer_Job *job = _job_new(source, target);
+
+ Eina_Bool ret;
+ if (options)
+ ret = ecore_file_download_full(source,
+ target,
+ _download_completion_cb,
+ _download_progress_cb,
+ pd,
+ &job->download,
+ options);
+ else
+ ret = ecore_file_download(source,
+ target,
+ _download_completion_cb,
+ _download_progress_cb,
+ pd,
+ &job->download);
+
+ if (!ret)
+ {
+ _job_free(&job);
+ ERR("%s", "An error occurred downloading the file");
+ Ecordova_FileTransfer_Error error = {
+ .code = ECORDOVA_FILETRANSFER_ERRORCODE_ABORT_ERR,
+ .source = source,
+ .target = target,
+ .http_status = 0,
+ .body = NULL,
+ .exception = "An error occurred downloading the file"
+ };
+ eo_do(obj, eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_ERROR, &error));
+ return;
+ }
+
+ pd->job = job;
+}
+
+static void
+_ecordova_filetransfer_abort(Eo *obj, Ecordova_FileTransfer_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ if (!pd->job) return;
+
+ if (pd->job->download)
+ ecore_file_download_abort(pd->job->download);
+ else
+ ecore_thread_cancel(pd->job->upload);
+}
+
+static int
+_download_progress_cb(void *data,
+ const char *file EINA_UNUSED,
+ long int dltotal,
+ long int dlnow,
+ long int ultotal EINA_UNUSED,
+ long int ulnow EINA_UNUSED)
+{
+ Ecordova_FileTransfer_Data *pd = data;
+ DBG("(%p)", pd->obj);
+ Ecordova_ProgressEvent event = {
+ .type = "download",
+ .cancelable = true,
+ .length_computable = true,
+ .loaded = dlnow,
+ .total = dltotal,
+ .target = pd->obj
+ };
+ _progress_notify(pd, &event);
+ return ECORE_FILE_PROGRESS_CONTINUE;
+}
+
+static void
+_download_completion_cb(void *data, const char *file, int status)
+{
+ Ecordova_FileTransfer_Data *pd = data;
+ DBG("(%p)", pd->obj);
+ if (1 == status)
+ _abort_error_notify(pd);
+ else if (200 != status)
+ _status_error_notify(pd, status);
+ else
+ {
+ char *path, *name, *native;
+ split_path(NULL, file, &path, &name, &native);
+
+ Ecordova_FileEntry *file_entry = eo_add(ECORDOVA_FILEENTRY_CLASS, NULL,
+ ecordova_fileentry_constructor(name, path, NULL, native)); // TODO: filesystem?
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_DOWNLOAD_SUCCESS, file_entry));
+ eo_unref(file_entry);
+
+ free(path);
+ free(name);
+ free(native);
+ }
+
+ _clear(pd);
+}
+
+static void
+_clear(Ecordova_FileTransfer_Data *pd)
+{
+ DBG("(%p)", pd->obj);
+ _job_free(&pd->job);
+}
+
+static void
+_upload_cb(void *data, Ecore_Thread *thread)
+{
+ Ecordova_FileTransfer_Data *pd = data;
+ DBG("(%p)", pd->obj);
+
+ if (ecore_thread_check(thread))
+ {
+ pd->job->upload_error = 1;
+ return;
+ }
+
+ FILE *stream = fopen(pd->job->source, "rb");
+ if (!stream)
+ {
+ pd->job->upload_error = errno;
+ return;
+ }
+
+ int error = fseek(stream, 0L, SEEK_END);
+ if (error)
+ {
+ pd->job->upload_error = errno;
+ goto on_error;
+ }
+
+ pd->job->upload_length = ftell(stream);
+ if (pd->job->upload_length < 0)
+ {
+ pd->job->upload_error = errno;
+ goto on_error;
+ }
+
+ error = fseek(stream, 0L, SEEK_SET);
+ {
+ pd->job->upload_error = errno;
+ goto on_error;
+ }
+
+ _upload_progress_notify(0, pd->job->upload_length, pd->obj, thread);
+
+ pd->job->upload_buffer = malloc(pd->job->upload_length);
+ if (!pd->job->upload_buffer)
+ {
+ pd->job->upload_error = errno;
+ goto on_error;
+ }
+
+ long int total_read = 0;
+ while (total_read < pd->job->upload_length)
+ {
+ size_t read = fread(&pd->job->upload_buffer[total_read],
+ sizeof(char),
+ pd->job->upload_length - total_read,
+ stream);
+ total_read += read;
+
+ _upload_progress_notify(0, pd->job->upload_length, pd->obj, thread);
+ if (ecore_thread_check(thread))
+ {
+ pd->job->upload_error = 1;
+ break;
+ }
+ }
+
+on_error:
+ fclose(stream);
+}
+
+static void
+_upload_progress_notify(size_t uploaded,
+ size_t total,
+ Eo *obj,
+ Ecore_Thread *thread)
+{
+ DBG("(%p)", obj);
+
+ Ecordova_ProgressEvent *progress = malloc(sizeof(Ecordova_ProgressEvent));
+ *progress = (Ecordova_ProgressEvent)
+ {
+ .type = "upload",
+ .length_computable = EINA_TRUE,
+ .loaded = uploaded,
+ .total = total,
+ .target = obj
+ };
+ if (!ecore_thread_feedback(thread, progress))
+ free(progress);
+}
+
+static void
+_upload_progress_cb(void *data,
+ Ecore_Thread *thread EINA_UNUSED,
+ void *msg_data)
+{
+ Ecordova_FileTransfer_Data *pd = data;
+ DBG("(%p)", pd->obj);
+ Ecordova_ProgressEvent *event = msg_data;
+ _progress_notify(pd, event);
+ free(event);
+}
+
+static void
+_upload_end_cb(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+ Ecordova_FileTransfer_Data *pd = data;
+ DBG("(%p)", pd->obj);
+
+ if (1 == pd->job->upload_error)
+ _abort_error_notify(pd);
+ else if (pd->job->upload_error)
+ _file_error_notify(pd, pd->job->upload_error);
+ else
+ {
+ pd->job->upload_con_url = ecore_con_url_custom_new(pd->job->target,
+ pd->job->upload_options.http_method);
+ if (!pd->job->upload_con_url)
+ {
+ _connection_error_notify(pd);
+ goto on_error;
+ }
+
+ pd->job->complete_event_hanbler = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, _url_complete_cb, pd);
+ pd->job->progress_event_hanbler = ecore_event_handler_add(ECORE_CON_EVENT_URL_PROGRESS, _url_progress_cb, pd);
+ if (!pd->job->complete_event_hanbler || !pd->job->progress_event_hanbler)
+ {
+ _connection_error_notify(pd);
+ goto on_error;
+ }
+
+ if (pd->job->upload_options.headers)
+ {
+ Eina_Iterator *it = eina_hash_iterator_tuple_new(pd->job->upload_options.headers);
+ Eina_Hash_Tuple *tuple;
+ EINA_ITERATOR_FOREACH(it, tuple)
+ ecore_con_url_additional_header_add(pd->job->upload_con_url, tuple->key, tuple->data);
+ eina_iterator_free(it);
+ }
+
+ Eina_Bool ret = ecore_con_url_post(pd->job->upload_con_url,
+ pd->job->upload_buffer,
+ pd->job->upload_length,
+ pd->job->upload_options.mime_type);
+ if (!ret)
+ {
+ _connection_error_notify(pd);
+ goto on_error;
+ }
+
+ return;
+ }
+
+on_error:
+ _clear(pd);
+}
+
+static void
+_upload_abort_cb(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+ Ecordova_FileTransfer_Data *pd = data;
+ DBG("(%p)", pd->obj);
+
+ _abort_error_notify(pd);
+ _clear(pd);
+}
+
+static void
+_progress_notify(Ecordova_FileTransfer_Data *pd,
+ Ecordova_ProgressEvent *event)
+{
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_ON_PROGRESS, event));
+}
+
+static Ecordova_FileTransfer_Job *
+_job_new(const char *source, const char *target)
+{
+ Ecordova_FileTransfer_Job *job = calloc(1, sizeof(Ecordova_FileTransfer_Job));
+ job->source = strdup(source);
+ job->target = strdup(target);
+ job->upload_options = (Ecordova_FileTransfer_UploadOptions){
+ .file_key = "file",
+ .file_name = "image.jpg",
+ .http_method = "POST",
+ .mime_type = "image/jpeg",
+ .chunked_mode = EINA_TRUE
+ };
+ return job;
+}
+
+static void
+_job_free(Ecordova_FileTransfer_Job **job)
+{
+ if (!*job) return;
+
+ if ((*job)->upload_con_url)
+ {
+ if ((*job)->progress_event_hanbler)
+ ecore_event_handler_del((*job)->progress_event_hanbler);
+ if ((*job)->complete_event_hanbler)
+ ecore_event_handler_del((*job)->complete_event_hanbler);
+ ecore_con_url_free((*job)->upload_con_url);
+ }
+ free((*job)->upload_buffer);
+ free((*job)->source);
+ free((*job)->target);
+ free(*job);
+ *job = NULL;
+}
+
+static Eina_Bool
+_url_progress_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info)
+{
+ Ecore_Con_Event_Url_Progress *url_progress = event_info;
+ Ecordova_FileTransfer_Data *pd = data;
+
+ Ecordova_ProgressEvent event = {
+ .type = "upload",
+ .cancelable = false,
+ .length_computable = true,
+ .loaded = url_progress->up.now,
+ .total = url_progress->up.total,
+ .target = pd->obj
+ };
+ _progress_notify(pd, &event);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_url_complete_cb(void *data, int type EINA_UNUSED, void *event_info)
+{
+ Ecore_Con_Event_Url_Complete *url_complete = event_info;
+ Ecordova_FileTransfer_Data *pd = data;
+
+ if (200 != url_complete->status)
+ _status_error_notify(pd, url_complete->status);
+ else
+ {
+ Eina_Hash *headers_hash = NULL;
+ const Eina_List *headers = ecore_con_url_response_headers_get(url_complete->url_con);
+ if (eina_list_count(headers))
+ {
+ headers_hash = eina_hash_string_superfast_new(free);
+ const char *header_line;
+ const Eina_List *it;
+ EINA_LIST_FOREACH(headers, it, header_line)
+ {
+ const char *separator = strchr(header_line, ':');
+ if (!separator) continue;
+
+ size_t key_len = separator - header_line + 1;
+ char key[key_len];
+ strncpy(key, header_line, key_len);
+ key[key_len - 1] = '\0';
+
+ if (*(++separator) == ' ')
+ ++separator;
+ char *value = strdup(separator);
+ eina_hash_add(headers_hash, key, value);
+ }
+ }
+
+ Ecordova_FileTransfer_UploadResult result = {
+ .bytes_sent = pd->job->upload_length,
+ .response_code = url_complete->status,
+ .headers = headers_hash,
+ .response = NULL // TODO: Get the HTTP response
+ };
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_UPLOAD_SUCCESS,
+ &result));
+ if (headers_hash)
+ eina_hash_free(headers_hash);
+ }
+
+ _clear(pd);
+ return EINA_TRUE;
+}
+
+static void
+_abort_error_notify(Ecordova_FileTransfer_Data *pd)
+{
+ INF("%s", "Aborted");
+ Ecordova_FileTransfer_Error error = {
+ .code = ECORDOVA_FILETRANSFER_ERRORCODE_ABORT_ERR,
+ .source = pd->job->source,
+ .target = pd->job->target,
+ .http_status = 0,
+ .body = NULL,
+ .exception = "Aborted"
+ };
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_ERROR, &error));
+}
+
+static void
+_status_error_notify(Ecordova_FileTransfer_Data *pd, int status)
+{
+ ERR("Error status: %d", status);
+ Ecordova_FileTransfer_Error error = {
+ // TODO: translate other errors checking first which protocol it is.
+ .code = 404 == status ? ECORDOVA_FILETRANSFER_ERRORCODE_FILE_NOT_FOUND_ERR :
+ ECORDOVA_FILETRANSFER_ERRORCODE_ABORT_ERR,
+ .source = pd->job->source,
+ .target = pd->job->target,
+ .http_status = status,
+ .body = NULL,
+ .exception = "Error"
+ };
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_ERROR, &error));
+}
+
+static void
+_file_error_notify(Ecordova_FileTransfer_Data *pd, int code)
+{
+ ERR("Error code: %d", code);
+ Ecordova_FileTransfer_Error error = {
+ .code = ECORDOVA_FILETRANSFER_ERRORCODE_FILE_NOT_FOUND_ERR,
+ .source = pd->job->source,
+ .target = pd->job->target,
+ .http_status = 0,
+ .body = NULL,
+ .exception = "Internal error"
+ };
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_ERROR, &error));
+}
+
+static void
+_connection_error_notify(Ecordova_FileTransfer_Data *pd)
+{
+ ERR("%s", "Connection error");
+ Ecordova_FileTransfer_Error error = {
+ .code = ECORDOVA_FILETRANSFER_ERRORCODE_CONNECTION_ERR,
+ .source = pd->job->source,
+ .target = pd->job->target,
+ .http_status = 0,
+ .body = NULL,
+ .exception = "Connection error"
+ };
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_ERROR, &error));
+}
+
+static void
+_already_in_progress_error_notify(Ecordova_FileTransfer_Data *pd,
+ const char *source,
+ const char *target)
+{
+ ERR("%s", "A job is already in progress");
+ Ecordova_FileTransfer_Error error = {
+ .code = ECORDOVA_FILETRANSFER_ERRORCODE_ABORT_ERR,
+ .source = source,
+ .target = target,
+ .http_status = 0,
+ .body = NULL,
+ .exception = "A job is already in progress"
+ };
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_ERROR, &error));
+}
+
+#include "ecordova_filetransfer.eo.c"
diff --git a/src/lib/ecordova/ecordova_filetransfer.eo b/src/lib/ecordova/ecordova_filetransfer.eo
new file mode 100644
index 0000000000..19faa3d298
--- /dev/null
+++ b/src/lib/ecordova/ecordova_filetransfer.eo
@@ -0,0 +1,155 @@
+struct Ecordova_FileTransfer_UploadOptions {
+ file_key: const(char)*;
+ [[The name of the form element. Defaults to file.]]
+
+ file_name: const(char)*;
+ [[The file name to use when saving the file on the server. Defaults to image.jpg.]]
+
+ http_method: const(char)*;
+ [[The HTTP method to use - either PUT or POST. Defaults to POST.]]
+
+ mime_type: const(char)*;
+ [[The mime type of the data to upload. Defaults to image/jpeg.]]
+
+ params: hash<const(char)*, const(char)*>*;
+ [[A set of optional key/value pairs to pass in the HTTP request.]]
+
+ chunked_mode: bool;
+ [[Whether to upload the data in chunked streaming mode. Defaults to true.]]
+
+ headers: hash<const(char)*, const(char)*>*;
+ [[A map of header name/header values. Use an array to specify more than one value.]]
+}
+
+struct Ecordova_FileTransfer_UploadResult {
+ bytes_sent: long;
+ [[The number of bytes sent to the server as part of the upload.]]
+
+ response_code: long;
+ [[The HTTP response code returned by the server.]]
+
+ response: const(char)*;
+ [[The HTTP response returned by the server.]]
+
+ headers: hash<const(char)*, const(char)*>*;
+ [[The HTTP response headers by the server.]]
+}
+
+enum Ecordova_FileTransfer_ErrorCode {
+ FILE_NOT_FOUND_ERR = 1,
+ INVALID_URL_ERR = 2,
+ CONNECTION_ERR = 3,
+ ABORT_ERR = 4,
+ NOT_MODIFIED_ERR = 5
+}
+
+struct Ecordova_FileTransfer_Error {
+ [[A FileTransferError object is passed to an error callback when an error occurs.]]
+
+ code: int;
+ [[One of the predefined error codes listed above.]]
+
+ source: const(char)*;
+ [[URL to the source.]]
+
+ target: const(char)*;
+ [[URL to the target.]]
+
+ http_status: int;
+ [[HTTP status code. This attribute is only available when a response code is received from the HTTP connection.]]
+
+ body: const(char)*;
+ [[Response body. This attribute is only available when a response is received from the HTTP connection.]]
+
+ exception: const(char)*;
+ [[Either e.getMessage or e.toString]]
+}
+
+struct Ecordova.ProgressEvent;
+
+class Ecordova.FileTransfer (Eo.Base) {
+ [[Ecordova File-Transfer Plugin
+ Plugin ID: org.apache.cordova.file-transfer
+ http://plugins.cordova.io/#/package/org.apache.cordova.file-transfer
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_FileTransfer constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ }
+ upload {
+ [[sends a file to a server.]]
+ params {
+ file_url: const(char)*;
+ [[Filesystem URL representing the file on the device. For
+ backwards compatibility, this can also be the full path of
+ the file on the device.]]
+
+ server: const(char)*;
+ [[URL of the server to receive the file, as encoded by
+ encodeURI().]]
+
+ options: Ecordova_FileTransfer_UploadOptions*;
+ [[Optional parameters]]
+
+ trust_all_hosts: bool;
+ [[Optional parameter, defaults to false. If set to true, it
+ accepts all security certificates. This is useful since
+ Android rejects self-signed security certificates. Not
+ recommended for production use.]]
+ }
+ }
+ download {
+ [[downloads a file from server.]]
+ params {
+ source: const(char)*;
+ [[URL of the server to download the file, as encoded by
+ encodeURI().]]
+
+ target: const(char)*;
+ [[Filesystem url representing the file on the device. For
+ backwards compatibility, this can also be the full path of
+ the file on the device]]
+
+ trust_all_hosts: bool;
+ [[Optional parameter, defaults to false. If set to true, it
+ accepts all security certificates. This is useful since
+ Android rejects self-signed security certificates. Not
+ recommended for production use.]]
+
+ options: hash<const(char)*, const(char)*>*;
+ [[Optional parameters, currently only supports headers (such
+ as Authorization (Basic Authentication), etc).]]
+ }
+ }
+ abort {
+ [[Aborts an in-progress transfer.]]
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ upload,success: const(Ecordova_FileTransfer_UploadResult)*;
+ [[A callback that is passed a FileUploadResult object.]]
+
+ download,success: Ecordova.FileEntry*;
+ [[callback that is passed a FileEntry object.]]
+
+ error: Ecordova_FileTransfer_Error*;
+ [[A callback that executes if an error occurs. Invoked with a
+ FileTransferError object.]]
+
+ on,progress: const(Ecordova.ProgressEvent)*;
+ [[Called with a ProgressEvent whenever a new chunk of data is
+ transferred.]]
+ }
+}
diff --git a/src/lib/ecordova/ecordova_filetransfer_private.h b/src/lib/ecordova/ecordova_filetransfer_private.h
new file mode 100644
index 0000000000..b17fe85e9a
--- /dev/null
+++ b/src/lib/ecordova/ecordova_filetransfer_private.h
@@ -0,0 +1,21 @@
+#ifndef _ECORDOVA_FILETRANSFER_PRIVATE_H
+#define _ECORDOVA_FILETRANSFER_PRIVATE_H
+
+#include "ecordova_private.h"
+
+#include <Ecore_File.h>
+
+typedef struct _Ecordova_FileTransfer_Data Ecordova_FileTransfer_Data;
+
+typedef struct _Ecordova_FileTransfer_Job Ecordova_FileTransfer_Job;
+
+/**
+ * Ecordova.FileTransfer private data
+ */
+struct _Ecordova_FileTransfer_Data
+{
+ Eo *obj;
+ Ecordova_FileTransfer_Job *job;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_filewriter.c b/src/lib/ecordova/ecordova_filewriter.c
new file mode 100644
index 0000000000..514e1f4456
--- /dev/null
+++ b/src/lib/ecordova/ecordova_filewriter.c
@@ -0,0 +1,357 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_filewriter_private.h"
+#include "ecordova_entry_private.h"
+
+#include <stdbool.h>
+#include <unistd.h>
+
+#define MY_CLASS ECORDOVA_FILEWRITER_CLASS
+#define MY_CLASS_NAME "Ecordova_FileWriter"
+
+static void _write_cb(void *, Ecore_Thread *);
+static void _truncate_cb(void *, Ecore_Thread *);
+static bool _stream_init(Ecordova_FileWriter_Data *);
+static bool _offset_set(Ecordova_FileWriter_Data *);
+static void _write_end_cb(void *, Ecore_Thread *);
+static void _write_abort_cb(void *, Ecore_Thread *);
+static void _write_progress_cb(void *, Ecore_Thread *, void *);
+static void _progress_notify(size_t, size_t, Eo *, Ecore_Thread *);
+
+static Eo_Base *
+_ecordova_filewriter_eo_base_constructor(Eo *obj,
+ Ecordova_FileWriter_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->error = 0;
+ pd->error = ECORDOVA_FILEWRITER_STATE_INIT;
+ pd->url = NULL;
+ pd->offset = 0;
+ pd->length = 0;
+ pd->stream = NULL;
+ pd->data = NULL;
+ pd->data_size = 0;
+ pd->truncate_size = 0;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_filewriter_constructor(Eo *obj,
+ Ecordova_FileWriter_Data *pd,
+ Ecordova_File *file)
+{
+ DBG("(%p)", obj);
+ EINA_SAFETY_ON_NULL_RETURN(file);
+
+ eo_do(file,
+ pd->url = strdup(ecordova_file_url_get()),
+ pd->offset = ecordova_file_start_get(),
+ pd->length = ecordova_file_end_get() - pd->offset);
+}
+
+static void
+_ecordova_filewriter_eo_base_destructor(Eo *obj,
+ Ecordova_FileWriter_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ if (pd->thread) ERR("%s", "Destructing without aborting first");
+
+ free(pd->url);
+ if (pd->stream)
+ fclose(pd->stream);
+ if (pd->data)
+ free(pd->data);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static Ecordova_FileError
+_ecordova_filewriter_abort(Eo *obj, Ecordova_FileWriter_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ if (ECORDOVA_FILEWRITER_STATE_DONE == pd->state ||
+ ECORDOVA_FILEWRITER_STATE_INIT == pd->state)
+ return ECORDOVA_FILEERROR_INVALID_STATE_ERR;
+ pd->state = ECORDOVA_FILEWRITER_STATE_DONE;
+ pd->error = ECORDOVA_FILEERROR_ABORT_ERR;
+
+ if (pd->thread)
+ ecore_thread_cancel(pd->thread);
+
+ return 0;
+}
+
+static Ecordova_FileError
+_ecordova_filewriter_write(Eo *obj,
+ Ecordova_FileWriter_Data *pd,
+ const char *data,
+ long size)
+{
+ DBG("(%p)", obj);
+
+ if (ECORDOVA_FILEWRITER_STATE_WRITING == pd->state)
+ return ECORDOVA_FILEERROR_INVALID_STATE_ERR;
+ pd->state = ECORDOVA_FILEWRITER_STATE_WRITING;
+ pd->error = 0;
+
+ Ecordova_ProgressEvent writestart = {.type = "writestart", .target = obj};
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_FILEWRITER_EVENT_ON_WRITE_START,
+ &writestart));
+
+ pd->data_size = size ? size : (long)strlen(data);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(pd->data_size > 0, ECORDOVA_FILEERROR_SYNTAX_ERR);
+
+ pd->data = pd->data ? realloc(pd->data, pd->data_size) : malloc(pd->data_size);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pd->data, ECORDOVA_FILEERROR_SYNTAX_ERR);
+
+ memcpy(pd->data, data, pd->data_size);
+
+ pd->thread = ecore_thread_feedback_run(_write_cb,
+ _write_progress_cb,
+ _write_end_cb,
+ _write_abort_cb,
+ pd,
+ EINA_FALSE);
+ return 0;
+}
+
+static Ecordova_FileError
+_ecordova_filewriter_seek(Eo *obj, Ecordova_FileWriter_Data *pd, long offset)
+{
+ DBG("(%p)", obj);
+ if (ECORDOVA_FILEWRITER_STATE_WRITING == pd->state)
+ return ECORDOVA_FILEERROR_INVALID_STATE_ERR;
+
+ if (offset < 0)
+ pd->offset = MAX(offset + pd->length, 0);
+ else if (offset > pd->length)
+ pd->offset = pd->length;
+ else
+ pd->offset = offset;
+
+ return 0;
+}
+
+static Ecordova_FileError
+_ecordova_filewriter_truncate(Eo *obj, Ecordova_FileWriter_Data *pd, long size)
+{
+ DBG("(%p)", obj);
+
+ if (ECORDOVA_FILEWRITER_STATE_WRITING == pd->state)
+ return ECORDOVA_FILEERROR_INVALID_STATE_ERR;
+ pd->state = ECORDOVA_FILEWRITER_STATE_WRITING;
+ pd->error = 0;
+ pd->truncate_size = size;
+
+ pd->thread = ecore_thread_run(_truncate_cb,
+ _write_end_cb,
+ _write_abort_cb,
+ pd);
+ return 0;
+}
+
+static Ecordova_FileError
+_ecordova_filewriter_error_get(Eo *obj, Ecordova_FileWriter_Data *pd)
+{
+ DBG("(%p)", obj);
+ return pd->error;
+}
+
+static long
+_ecordova_filewriter_position_get(Eo *obj, Ecordova_FileWriter_Data *pd)
+{
+ DBG("(%p)", obj);
+ return pd->offset;
+}
+
+static Ecordova_FileWriter_State
+_ecordova_filewriter_state_get(Eo *obj, Ecordova_FileWriter_Data *pd)
+{
+ DBG("(%p)", obj);
+ return pd->state;
+}
+
+static void
+_write_cb(void *data, Ecore_Thread *thread)
+{
+ Ecordova_FileWriter_Data *pd = data;
+ DBG("(%p)", pd->obj);
+
+ if (ecore_thread_check(thread))
+ return;
+
+ if (!pd->stream && !_stream_init(pd))
+ return;
+
+ if (!_offset_set(pd))
+ return;
+
+ _progress_notify(0, pd->data_size, pd->obj, thread);
+ if (ecore_thread_check(thread))
+ return;
+
+ size_t total = pd->data_size;
+ char *buffer = pd->data;
+ do
+ {
+ size_t written = fwrite(buffer, sizeof(char), total, pd->stream);
+ if (!written)
+ {
+ pd->error = _translate_errno(errno);
+ return;
+ }
+
+ buffer += written;
+ total -= written;
+ pd->offset += written;
+
+ _progress_notify(pd->data_size - total, pd->data_size, pd->obj, thread);
+ if (ecore_thread_check(thread))
+ return;
+ }
+ while (total > 0);
+
+ pd->length = MAX(pd->offset, pd->length);
+}
+
+static void
+_truncate_cb(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+ Ecordova_FileWriter_Data *pd = data;
+ DBG("(%p)", pd->obj);
+
+ if (ecore_thread_check(thread))
+ return;
+
+ if (!pd->stream && !_stream_init(pd))
+ return;
+
+ if (!_offset_set(pd))
+ return;
+
+ if (ftruncate(fileno(pd->stream), pd->truncate_size) != 0)
+ {
+ pd->error = _translate_errno(errno);
+ return;
+ }
+
+ pd->length = pd->truncate_size;
+ pd->offset = MIN(pd->offset, pd->truncate_size);
+}
+
+static bool
+_stream_init(Ecordova_FileWriter_Data *pd)
+{
+ pd->stream = fopen(pd->url, "rb+");
+ if (!pd->stream)
+ {
+ pd->error = _translate_errno(errno);
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+_offset_set(Ecordova_FileWriter_Data *pd)
+{
+ int error = fseek(pd->stream, pd->offset, SEEK_SET);
+ if (error)
+ {
+ pd->error = _translate_errno(errno);
+ return false;
+ }
+
+ return true;
+}
+
+static void
+_progress_notify(size_t written, size_t total, Eo *obj, Ecore_Thread *thread)
+{
+ Ecordova_ProgressEvent *progress = malloc(sizeof(Ecordova_ProgressEvent));
+ *progress = (Ecordova_ProgressEvent)
+ {
+ .type = "progress",
+ .length_computable = EINA_TRUE,
+ .loaded = written,
+ .total = total,
+ .target = obj
+ };
+ if (!ecore_thread_feedback(thread, progress))
+ free(progress);
+}
+
+static void
+_write_progress_cb(void *data,
+ Ecore_Thread *thread EINA_UNUSED,
+ void *msg_data)
+{
+ Ecordova_FileWriter_Data *pd = data;
+ DBG("(%p)", pd->obj);
+ Ecordova_ProgressEvent *event = msg_data;
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILEWRITER_EVENT_ON_PROGRESS, &event));
+ free(event);
+}
+
+static void
+_write_end_cb(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+ Ecordova_FileWriter_Data *pd = data;
+ DBG("(%p)", pd->obj);
+
+ // If DONE (cancelled), then don't do anything
+ if (ECORDOVA_FILEWRITER_STATE_DONE == pd->state)
+ return;
+ pd->thread = NULL;
+ pd->state = ECORDOVA_FILEWRITER_STATE_DONE;
+
+ if (pd->error)
+ {
+ Ecordova_ProgressEvent error = {.type = "error", .target = pd->obj};
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILEWRITER_EVENT_ON_ERROR,
+ &error));
+ }
+ else
+ {
+ Ecordova_ProgressEvent write = {.type = "write", .target = pd->obj};
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILEWRITER_EVENT_ON_WRITE,
+ &write));
+ }
+
+ Ecordova_ProgressEvent writeend = {.type = "writeend", .target = pd->obj};
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILEWRITER_EVENT_ON_WRITE_END,
+ &writeend));
+}
+
+static void
+_write_abort_cb(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+ Ecordova_FileWriter_Data *pd = data;
+ DBG("(%p)", pd->obj);
+
+ pd->thread = NULL;
+
+ Ecordova_ProgressEvent on_abort = {.type = "abort", .target = pd->obj};
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILEWRITER_EVENT_ON_ABORT,
+ &on_abort));
+
+ Ecordova_ProgressEvent writeend = {.type = "writeend", .target = pd->obj};
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_FILEWRITER_EVENT_ON_WRITE_END,
+ &writeend));
+}
+
+#include "ecordova_filewriter.eo.c"
diff --git a/src/lib/ecordova/ecordova_filewriter.eo b/src/lib/ecordova/ecordova_filewriter.eo
new file mode 100644
index 0000000000..6a3f9a1a5c
--- /dev/null
+++ b/src/lib/ecordova/ecordova_filewriter.eo
@@ -0,0 +1,112 @@
+enum Ecordova_FileWriter_State {
+ INIT = 0,
+ WRITING = 1,
+ DONE = 2
+}
+
+enum Ecordova_FileError {
+ NOT_FOUND_ERR = 1,
+ SECURITY_ERR = 2,
+ ABORT_ERR = 3,
+ NOT_READABLE_ERR = 4,
+ ENCODING_ERR = 5,
+ NO_MODIFICATION_ALLOWED_ERR = 6,
+ INVALID_STATE_ERR = 7,
+ SYNTAX_ERR = 8,
+ INVALID_MODIFICATION_ERR = 9,
+ QUOTA_EXCEEDED_ERR = 10,
+ TYPE_MISMATCH_ERR = 11,
+ PATH_EXISTS_ERR = 12
+}
+
+class Ecordova.FileWriter (Eo.Base) {
+ [[This class writes to the device file system.]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_FileWriter constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ params {
+ file: Ecordova.File*; [[File object containing file properties]]
+ }
+ }
+ abort {
+ [[Abort writing file.]]
+ return: Ecordova_FileError;
+ }
+ write {
+ [[Writes data to the file]]
+ params {
+ data: const(char)*; [[text or blob to be written]]
+ size: long; [[the blob's size]]
+ }
+ return: Ecordova_FileError;
+ }
+ seek {
+ [[Moves the file pointer to the location specified.
+
+ If the offset is a negative number the position of the file
+ pointer is rewound. If the offset is greater than the file
+ size the position is set to the end of the file.]]
+ params {
+ offset: long; [[location to move the file pointer to.]]
+ }
+ return: Ecordova_FileError;
+ }
+ truncate {
+ [[Truncates the file to the size specified.]]
+ params {
+ size: long; [[size to chop the file at.]]
+ }
+ return: Ecordova_FileError;
+ }
+ @property error {
+ get {}
+ values {
+ value: Ecordova_FileError;
+ }
+ }
+ @property position {
+ get {}
+ values {
+ state: long;
+ }
+ }
+ @property state {
+ get {}
+ values {
+ state: Ecordova_FileWriter_State;
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ on,write,start: const(ProgressEvent)*;
+ [[When writing starts]]
+
+ on,progress: const(ProgressEvent)*;
+ [[While writing the file, and reporting partial file data]]
+
+ on,write: const(ProgressEvent)*;
+ [[When the write has successfully completed.]]
+
+ on,write,end: const(ProgressEvent)*;
+ [[When the request has completed (either in success or failure).]]
+
+ on,abort: const(ProgressEvent)*;
+ [[When the write has been aborted. For instance, by invoking the abort()
+ method.]]
+
+ on,error: const(ProgressEvent)*;
+ [[When the write has failed (see errors).]]
+ }
+}
diff --git a/src/lib/ecordova/ecordova_filewriter_private.h b/src/lib/ecordova/ecordova_filewriter_private.h
new file mode 100644
index 0000000000..459d1c671f
--- /dev/null
+++ b/src/lib/ecordova/ecordova_filewriter_private.h
@@ -0,0 +1,26 @@
+#ifndef _ECORDOVA_FILEWRITER_PRIVATE_H
+#define _ECORDOVA_FILEWRITER_PRIVATE_H
+
+#include "ecordova_private.h"
+
+typedef struct _Ecordova_FileWriter_Data Ecordova_FileWriter_Data;
+
+/**
+ * Ecordova.FileWriter private data
+ */
+struct _Ecordova_FileWriter_Data
+{
+ Eo *obj;
+ Ecordova_FileError error;
+ Ecordova_FileWriter_State state;
+ char *url;
+ long offset;
+ long length;
+ FILE *stream;
+ char *data;
+ long data_size;
+ long truncate_size;
+ Ecore_Thread *thread;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_geolocation.c b/src/lib/ecordova/ecordova_geolocation.c
new file mode 100644
index 0000000000..dff3e7b476
--- /dev/null
+++ b/src/lib/ecordova/ecordova_geolocation.c
@@ -0,0 +1,282 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_geolocation_private.h"
+#include <ecore_timer.eo.h>
+
+#define MY_CLASS ECORDOVA_GEOLOCATION_CLASS
+#define MY_CLASS_NAME "Ecordova_Geolocation"
+
+typedef struct
+{
+ Eo *obj;
+ location_manager_h manager;
+ Ecore_Timer *timer;
+ bool current;
+ bool is_ready;
+} Ecordova_Geolocation_Watch;
+
+static void _watch_free(Ecordova_Geolocation_Watch*);
+static Eina_Bool _interval_cb(void *);
+static void _state_changed_cb(location_service_state_e, void *);
+static void _notify(Ecordova_Geolocation_Watch *);
+static Ecordova_Geolocation_Watch *_create_watch(Eo *, const Ecordova_Geolocation_Options *, bool);
+
+static Eo_Base *
+_ecordova_geolocation_eo_base_constructor(Eo *obj,
+ Ecordova_Geolocation_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->watchers = eina_hash_int32_new(EINA_FREE_CB(_watch_free));
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_geolocation_constructor(Eo *obj EINA_UNUSED,
+ Ecordova_Geolocation_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+}
+
+static void
+_ecordova_geolocation_eo_base_destructor(Eo *obj,
+ Ecordova_Geolocation_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ eina_hash_free(pd->watchers);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_geolocation_current_position_get(Eo *obj,
+ Ecordova_Geolocation_Data *pd EINA_UNUSED,
+ const Ecordova_Geolocation_Options *options)
+{
+ Ecordova_Geolocation_Watch *watch = _create_watch(obj, options, true);
+ if (!watch)
+ {
+ Ecordova_Geolocation_Error error = {
+ .code = ECORDOVA_GEOLOCATION_ERRORCODE_PERMISSION_DENIED,
+ .message = "Unknown"
+ };
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GEOLOCATION_EVENT_ERROR, &error));
+ return;
+ }
+}
+
+static Ecordova_Geolocation_WatchID
+_ecordova_geolocation_position_watch(Eo *obj,
+ Ecordova_Geolocation_Data *pd,
+ const Ecordova_Geolocation_Options *options)
+{
+ Ecordova_Geolocation_Watch *watch = _create_watch(obj, options, false);
+ if (!watch)
+ {
+ Ecordova_Geolocation_Error error = {
+ .code = ECORDOVA_GEOLOCATION_ERRORCODE_PERMISSION_DENIED,
+ .message = "Unknown"
+ };
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GEOLOCATION_EVENT_ERROR, &error));
+ return 0;
+ }
+
+ watch->timer = eo_add(ECORE_TIMER_CLASS, NULL,
+ ecore_obj_timer_constructor(options->timeout / 1000.0, _interval_cb, watch));
+
+ static Ecordova_Geolocation_WatchID id = 0;
+ ++id;
+ eina_hash_add(pd->watchers, &id, watch);
+ return id;
+}
+
+static void
+_ecordova_geolocation_watch_clear(Eo *obj,
+ Ecordova_Geolocation_Data *pd,
+ Ecordova_Geolocation_WatchID watch_id)
+{
+ Ecordova_Geolocation_Watch *watch = eina_hash_find(pd->watchers, &watch_id);
+ if (!watch)
+ {
+ eo_do(obj, eo_event_callback_call(ECORDOVA_DEVICEORIENTATION_EVENT_ERROR,
+ NULL));
+ return;
+ }
+
+ Eina_Bool ret = eina_hash_del(pd->watchers, &watch_id, NULL);
+ EINA_SAFETY_ON_FALSE_RETURN(ret);
+}
+
+static void
+_watch_free(Ecordova_Geolocation_Watch *watch)
+{
+ if (watch->timer)
+ eo_unref(watch->timer);
+
+ int ret = location_manager_unset_service_state_changed_cb(watch->manager);
+ EINA_SAFETY_ON_FALSE_GOTO(LOCATIONS_ERROR_NONE != ret, on_error);
+
+ ret = location_manager_stop(watch->manager);
+ EINA_SAFETY_ON_FALSE_GOTO(LOCATIONS_ERROR_NONE != ret, on_error);
+
+ ret = location_manager_destroy(watch->manager);
+ EINA_SAFETY_ON_FALSE_GOTO(LOCATIONS_ERROR_NONE != ret, on_error);
+
+on_error:
+ free(watch);
+}
+
+static Eina_Bool
+_interval_cb(void *data)
+{
+ Ecordova_Geolocation_Watch *watch = data;
+ if (!watch->is_ready)
+ {
+ Ecordova_Geolocation_Error error = {
+ .code = ECORDOVA_GEOLOCATION_ERRORCODE_TIMEOUT,
+ .message = "Timeout"
+ };
+ eo_do(watch->obj,
+ eo_event_callback_call(ECORDOVA_GEOLOCATION_EVENT_ERROR, &error));
+ return ECORE_CALLBACK_RENEW;
+ }
+
+ _notify(watch);
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_state_changed_cb(location_service_state_e state, void *data)
+{
+ if (LOCATIONS_SERVICE_ENABLED != state)
+ return;
+
+ Ecordova_Geolocation_Watch *watch = data;
+ watch->is_ready = true;
+
+ if (watch->current)
+ {
+ _notify(watch);
+ _watch_free(watch);
+ }
+}
+
+static void
+_notify(Ecordova_Geolocation_Watch* watch)
+{
+ double altitude;
+ double latitude;
+ double longitude;
+ double climb;
+ double direction;
+ double speed;
+ location_accuracy_level_e level;
+ double horizontal;
+ double vertical;
+ time_t timestamp;
+
+ int ret = location_manager_get_location(watch->manager,
+ &altitude,
+ &latitude,
+ &longitude,
+ &climb,
+ &direction,
+ &speed,
+ &level,
+ &horizontal,
+ &vertical,
+ &timestamp);
+ if (LOCATIONS_ERROR_NONE != ret)
+ {
+ Ecordova_Geolocation_Error error = {0};
+ switch (ret)
+ {
+ case LOCATIONS_ERROR_INVALID_PARAMETER:
+ error.code = ECORDOVA_GEOLOCATION_ERRORCODE_POSITION_UNAVAILABLE;
+ error.message = "Invalid parameter";
+ break;
+ default:
+ error.code = ECORDOVA_GEOLOCATION_ERRORCODE_POSITION_UNAVAILABLE;
+ error.message = "Unknown";
+ break;
+ }
+ eo_do(watch->obj,
+ eo_event_callback_call(ECORDOVA_GEOLOCATION_EVENT_ERROR, &error));
+ return;
+ }
+
+ Ecordova_Geolocation_Position position = {
+ .coords = {
+ .latitude = latitude,
+ .longitude = longitude,
+ .altitude = altitude,
+ .accuracy = horizontal,
+ .altitude_accuracy = vertical,
+ .heading = direction,
+ .speed = speed / 3.6
+ },
+ .timestamp = timestamp
+ };
+
+ const Eo_Event_Description * const event =
+ watch->current ? ECORDOVA_GEOLOCATION_EVENT_CURRENT_SUCCESS
+ : ECORDOVA_GEOLOCATION_EVENT_WATCH_SUCCESS;
+ eo_do(watch->obj, eo_event_callback_call(event, &position));
+}
+
+static Ecordova_Geolocation_Watch *
+_create_watch(Eo *obj,
+ const Ecordova_Geolocation_Options *options,
+ bool is_current)
+{
+ const Ecordova_Geolocation_Options default_options = {
+ .enable_high_accuracy = EINA_FALSE,
+ .timeout = 1000,
+ .maximum_age = 0
+ };
+ if (!options)
+ options = &default_options;
+
+ Ecordova_Geolocation_Watch *watch = calloc(1, sizeof(Ecordova_Geolocation_Watch));
+ watch->obj = obj;
+ watch->current = is_current;
+
+ int ret = LOCATIONS_ERROR_NONE;
+
+ if (options->enable_high_accuracy)
+ ret = location_manager_create(LOCATIONS_METHOD_GPS, &watch->manager);
+ else
+ ret = location_manager_create(LOCATIONS_METHOD_GPS, &watch->manager);
+ EINA_SAFETY_ON_FALSE_GOTO(LOCATIONS_ERROR_NONE == ret, on_error_1);
+
+ ret = location_manager_set_service_state_changed_cb(watch->manager,
+ _state_changed_cb,
+ watch);
+ EINA_SAFETY_ON_FALSE_GOTO(LOCATIONS_ERROR_NONE == ret, on_error_2);
+
+ ret = location_manager_start(watch->manager);
+ EINA_SAFETY_ON_FALSE_GOTO(LOCATIONS_ERROR_NONE == ret, on_error_3);
+ return watch;
+
+on_error_3:
+ ret = location_manager_unset_service_state_changed_cb(watch->manager);
+ EINA_SAFETY_ON_FALSE_GOTO(LOCATIONS_ERROR_NONE == ret, on_error_2);
+
+on_error_2:
+ ret = location_manager_destroy(watch->manager);
+ EINA_SAFETY_ON_FALSE_GOTO(LOCATIONS_ERROR_NONE == ret, on_error_1);
+
+on_error_1:
+ free(watch);
+ return NULL;
+}
+
+#include "ecordova_geolocation.eo.c"
diff --git a/src/lib/ecordova/ecordova_geolocation.eo b/src/lib/ecordova/ecordova_geolocation.eo
new file mode 100644
index 0000000000..1339149d60
--- /dev/null
+++ b/src/lib/ecordova/ecordova_geolocation.eo
@@ -0,0 +1,152 @@
+type Ecordova_Geolocation_WatchID: int;
+
+struct Ecordova_Geolocation_Coordinates {
+ [[A Coordinates object is attached to a Position object that is available
+ to callback functions in requests for the current position. It contains
+ a set of properties that describe the geographic coordinates of a
+ position.]]
+
+ latitude: double;
+ [[Latitude in decimal degrees.]]
+
+ longitude: double;
+ [[Longitude in decimal degrees.]]
+
+ altitude: double;
+ [[Height of the position in meters above the ellipsoid.]]
+
+ accuracy: double;
+ [[Accuracy level of the latitude and longitude coordinates in meters.]]
+
+ altitude_accuracy: double;
+ [[Accuracy level of the altitude coordinate in meters.]]
+
+ heading: double;
+ [[Direction of travel, specified in degrees counting clockwise relative to
+ the true north.]]
+
+ speed: double;
+ [[Current ground speed of the device, specified in meters per second.]]
+}
+
+struct Ecordova_Geolocation_Position {
+ [[Contains Position coordinates and timestamp, created by the geolocation API.]]
+
+ coords: Ecordova_Geolocation_Coordinates;
+ [[A set of geographic coordinates.]]
+
+ timestamp: time;
+ [[Creation timestamp for coords.]]
+}
+
+struct Ecordova_Geolocation_Options {
+ enable_high_accuracy: bool;
+ [[Provides a hint that the application needs the best possible results. By
+ default, the device attempts to retrieve a Position using network-based
+ methods. Setting this property to true tells the framework to use more
+ accurate methods, such as satellite positioning.]]
+
+ timeout: int;
+ [[The maximum length of time (milliseconds) that is allowed to pass from
+ the call to navigator.geolocation.current_position_get or
+ geolocation.position_watch until the corresponding geolocationSuccess
+ callback executes. If the geolocationSuccess callback is not invoked
+ within this time, the geolocationError callback is passed a
+ PositionError.TIMEOUT error code. (Note that when used in conjunction
+ with geolocation.position_watch, the geolocationError callback could be
+ called on an interval every timeout milliseconds!)]]
+
+ maximum_age: int;
+ [[Accept a cached position whose age is no greater than the specified time
+ in milliseconds.]]
+}
+
+enum Ecordova_Geolocation_ErrorCode {
+ PERMISSION_DENIED,
+ [[Returned when users do not allow the app to retrieve position
+ information. This is dependent on the platform.]]
+
+ POSITION_UNAVAILABLE,
+ [[Returned when the device is unable to retrieve a position. In general,
+ this means the device is not connected to a network or can't get a
+ satellite fix.]]
+
+ TIMEOUT
+ [[Returned when the device is unable to retrieve a position within the
+ time specified by the timeout included in geolocationOptions. When used
+ with navigator.geolocation.position_watch, this error could be repeatedly
+ passed to the geolocationError callback every timeout milliseconds.]]
+}
+
+struct Ecordova_Geolocation_Error {
+ [[The PositionError object is passed to the geolocationError callback
+ function when an error occurs with navigator.geolocation.]]
+
+ code: int;
+ [[One of the predefined error codes listed above.]]
+
+ message: const(char)*;
+ [[Error message describing the details of the error encountered.]]
+}
+
+class Ecordova.Geolocation (Eo.Base) {
+ [[Ecordova Geolocation Plugin
+ Plugin ID: org.apache.cordova.geolocation
+ http://plugins.cordova.io/#/package/org.apache.cordova.geolocation
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_Geolocation constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ }
+ current_position_get {
+ [[Returns the device's current position to the geolocationSuccess
+ callback with a Position object as the parameter. If there is an
+ error, the geolocationError callback is passed a PositionError
+ object.]]
+ params {
+ options: const(Ecordova_Geolocation_Options)*;
+ [[The geolocation options.]]
+ }
+ }
+ position_watch {
+ [[Returns the device's current position when a change in position
+ is detected. When the device retrieves a new location, the
+ geolocationSuccess callback executes with a Position object as
+ the parameter. If there is an error, the geolocationError
+ callback executes with a PositionError object as the parameter.]]
+ params {
+ options: const(Ecordova_Geolocation_Options)*;
+ [[The geolocation options.]]
+ }
+ return: Ecordova_Geolocation_WatchID;
+ [[returns a watch id that references the watch position interval.
+ The watch id should be used with navigator.geolocation.watch_clear
+ to stop watching for changes in position.]]
+ }
+ watch_clear {
+ [[Stop watching for changes to the device's location referenced by
+ the watchID parameter.]]
+ params {
+ watch_id: Ecordova_Geolocation_WatchID;
+ [[The id of the position_watch interval to clear.]]
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ current,success: Ecordova_Geolocation_Position*;
+ watch,success: Ecordova_Geolocation_Position*;
+ error: Ecordova_Geolocation_Error*;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_geolocation_private.h b/src/lib/ecordova/ecordova_geolocation_private.h
new file mode 100644
index 0000000000..e31ad6eef6
--- /dev/null
+++ b/src/lib/ecordova/ecordova_geolocation_private.h
@@ -0,0 +1,19 @@
+#ifndef _ECORDOVA_GEOLOCATION_PRIVATE_H
+#define _ECORDOVA_GEOLOCATION_PRIVATE_H
+
+#include "ecordova_private.h"
+
+#include <locations.h>
+
+typedef struct _Ecordova_Geolocation_Data Ecordova_Geolocation_Data;
+
+/**
+ * Ecordova.Geolocation private data
+ */
+struct _Ecordova_Geolocation_Data
+{
+ Eo *obj;
+ Eina_Hash *watchers;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_globalization.c b/src/lib/ecordova/ecordova_globalization.c
new file mode 100644
index 0000000000..9320c87cdb
--- /dev/null
+++ b/src/lib/ecordova/ecordova_globalization.c
@@ -0,0 +1,1122 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_globalization_private.h"
+
+#include <utils_i18n.h>
+
+#define MY_CLASS ECORDOVA_GLOBALIZATION_CLASS
+#define MY_CLASS_NAME "Ecordova_Globalization"
+
+static void _date_time_options_to_style(const Ecordova_Globalization_DateTimeOptions *, i18n_udate_format_style_e *, i18n_udate_format_style_e *);
+
+
+static Eo_Base *
+_ecordova_globalization_eo_base_constructor(Eo *obj,
+ Ecordova_Globalization_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_globalization_constructor(Eo *obj EINA_UNUSED,
+ Ecordova_Globalization_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+}
+
+static void
+_ecordova_globalization_eo_base_destructor(Eo *obj,
+ Ecordova_Globalization_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_globalization_preferred_language_get(Eo *obj,
+ Ecordova_Globalization_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+ const char *locale;
+ int ret = i18n_ulocale_get_default(&locale);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error);
+
+ char language[64] = {0};
+ int32_t language_len;
+ ret = i18n_ulocale_get_language(locale,
+ language,
+ sizeof(language),
+ &language_len);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error);
+
+ Ecordova_Globalization_Language glanguage = {
+ .value = language
+ };
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_PREFERRED_LANGUAGE_SUCCESS,
+ &glanguage));
+ return;
+
+on_error:
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_ERROR,
+ &(Ecordova_Globalization_Error){
+ .code = ECORDOVA_GLOBALIZATION_ERRORCODE_UNKNOWN_ERROR,
+ .message = "Unknown error getting preferred language"
+ }));
+}
+
+static void
+_ecordova_globalization_locale_name_get(Eo *obj,
+ Ecordova_Globalization_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+ const char *locale;
+ int ret = i18n_ulocale_get_default(&locale);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error);
+
+ Ecordova_Globalization_Locale glocale = {
+ .value = locale
+ };
+ eo_do(obj, eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_LOCALE_NAME_SUCCESS,
+ &glocale));
+ return;
+
+on_error:
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_ERROR,
+ &(Ecordova_Globalization_Error){
+ .code = ECORDOVA_GLOBALIZATION_ERRORCODE_UNKNOWN_ERROR,
+ .message = "Unknown error getting locale name"
+ }));
+}
+
+static void
+_ecordova_globalization_date_to_string(Eo *obj,
+ Ecordova_Globalization_Data *pd EINA_UNUSED,
+ time_t date,
+ const Ecordova_Globalization_DateTimeOptions *options)
+{
+ DBG("(%p)", obj);
+
+ i18n_udate_format_style_e date_style;
+ i18n_udate_format_style_e time_style;
+ _date_time_options_to_style(options, &date_style, &time_style);
+
+ const char *locale;
+ int ret = i18n_ulocale_get_default(&locale);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_1);
+
+ i18n_udate_format_h format = NULL;
+ ret = i18n_udate_create(time_style,
+ date_style,
+ locale,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &format);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_1);
+
+ struct tm date_time;
+ localtime_r(&date, &date_time);
+
+ i18n_ucalendar_h calendar = NULL;
+ ret = i18n_ucalendar_create(NULL,
+ 0,
+ locale,
+ I18N_UCALENDAR_DEFAULT,
+ &calendar);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_1);
+
+ ret = i18n_ucalendar_set_date_time(calendar,
+ date_time.tm_year,
+ date_time.tm_mon,
+ date_time.tm_mday,
+ date_time.tm_hour,
+ date_time.tm_min,
+ date_time.tm_sec);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ i18n_udate udate;
+ ret = i18n_ucalendar_get_milliseconds(calendar, &udate);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ i18n_uchar uch_result[64] = {0};
+ int32_t uch_result_len;
+ ret = i18n_udate_format_date(format,
+ udate,
+ uch_result,
+ sizeof(uch_result),
+ NULL,
+ &uch_result_len);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ char result[64] = {0};
+ i18n_ustring_copy_au_n(result, uch_result, sizeof(uch_result));
+
+ Ecordova_Globalization_String gstring = {
+ .value = result
+ };
+ eo_do(obj, eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_DATE_TO_STRING_SUCCESS,
+ &gstring));
+
+ i18n_ucalendar_destroy(calendar);
+ i18n_udate_destroy(format);
+ return;
+
+on_error_2:
+ i18n_ucalendar_destroy(calendar);
+
+on_error_1:
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_ERROR,
+ &(Ecordova_Globalization_Error){
+ .code = ECORDOVA_GLOBALIZATION_ERRORCODE_UNKNOWN_ERROR,
+ .message = "Unknown error in date_to_string"
+ }));
+}
+
+static void
+_ecordova_globalization_currency_pattern_get(Eo *obj,
+ Ecordova_Globalization_Data *pd EINA_UNUSED,
+ const char *currency_code EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+
+ i18n_unumber_format_h num_format = NULL;
+ int ret = i18n_unumber_create(I18N_UNUMBER_CURRENCY,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ &num_format);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_1);
+
+
+ i18n_uchar uch_buffer[64] = {0};
+ int32_t uch_buffer_len;
+ ret = i18n_unumber_get_symbol(num_format,
+ I18N_UNUMBER_INTL_CURRENCY_SYMBOL,
+ uch_buffer,
+ sizeof(uch_buffer),
+ &uch_buffer_len);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+ char code[64] = {0};
+ i18n_ustring_copy_au_n(code, uch_buffer, sizeof(uch_buffer));
+
+
+ ret = i18n_unumber_get_symbol(num_format,
+ I18N_UNUMBER_DECIMAL_SEPARATOR_SYMBOL,
+ uch_buffer,
+ sizeof(uch_buffer),
+ &uch_buffer_len);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+ char decimal[64] = {0};
+ i18n_ustring_copy_au_n(decimal, uch_buffer, sizeof(uch_buffer));
+
+
+ ret = i18n_unumber_get_symbol(num_format,
+ I18N_UNUMBER_GROUPING_SEPARATOR_SYMBOL,
+ uch_buffer,
+ sizeof(uch_buffer),
+ &uch_buffer_len);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+ char grouping[64] = {0};
+ i18n_ustring_copy_au_n(grouping, uch_buffer, sizeof(uch_buffer));
+
+
+ int32_t len = i18n_unumber_to_pattern(num_format,
+ 1,
+ uch_buffer,
+ sizeof(uch_buffer));
+ ret = get_last_result();
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+ EINA_SAFETY_ON_TRUE_GOTO(len > (int32_t)sizeof(uch_buffer), on_error_2);
+ char pattern[64] = {0};
+ i18n_ustring_copy_au_n(pattern, uch_buffer, sizeof(uch_buffer));
+
+
+ double rounding = i18n_unumber_get_double_attribute(num_format,
+ I18N_UNUMBER_ROUNDING_INCREMENT);
+ ret = get_last_result();
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+ DBG("rounding: %f", rounding);
+
+
+ int32_t fraction = i18n_unumber_get_attribute(num_format,
+ I18N_UNUMBER_MAX_FRACTION_DIGITS);
+ ret = get_last_result();
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+ DBG("fraction: %d", fraction);
+
+ Ecordova_Globalization_CurrencyPattern number_pattern = {
+ .pattern = pattern,
+ .code = code,
+ .fraction = fraction,
+ .rounding = rounding,
+ .decimal = decimal,
+ .grouping = grouping
+ };
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_CURRENCY_PATTERN_SUCCESS,
+ &number_pattern));
+
+ i18n_unumber_destroy(num_format);
+ return;
+
+on_error_2:
+ i18n_unumber_destroy(num_format);
+
+on_error_1:
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_ERROR,
+ &(Ecordova_Globalization_Error){
+ .code = ECORDOVA_GLOBALIZATION_ERRORCODE_UNKNOWN_ERROR,
+ .message = "Unknown error getting currency pattern"
+ }));
+}
+
+static void
+_ecordova_globalization_date_names_get(Eo *obj,
+ Ecordova_Globalization_Data *pd EINA_UNUSED,
+ const Ecordova_Globalization_DateNamesOptions *options)
+{
+ DBG("(%p)", obj);
+ if (!options)
+ {
+ static const Ecordova_Globalization_DateNamesOptions default_options = {
+ .type = ECORDOVA_GLOBALIZATION_DATENAMESTYPE_WIDE,
+ .item = ECORDOVA_GLOBALIZATION_DATENAMESITEM_MONTHS
+ };
+ options = &default_options;
+ };
+
+ const char *locale;
+ int ret = i18n_ulocale_get_default(&locale);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_1);
+
+ i18n_udatepg_h dtpg = NULL;
+ ret = i18n_udatepg_create(locale, &dtpg);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_1);
+
+ const char *custom_format = NULL;
+ int count = 0;
+ switch (options->item)
+ {
+ case ECORDOVA_GLOBALIZATION_DATENAMESITEM_MONTHS:
+ count = 12;
+ if (ECORDOVA_GLOBALIZATION_DATENAMESTYPE_WIDE == options->type)
+ custom_format = "LLLL";
+ else
+ custom_format = "LLL";
+ break;
+ case ECORDOVA_GLOBALIZATION_DATENAMESITEM_DAYS:
+ count = 7;
+ if (ECORDOVA_GLOBALIZATION_DATENAMESTYPE_WIDE == options->type)
+ custom_format = "EEEE";
+ else
+ custom_format = "EEE";
+ break;
+ }
+
+ i18n_uchar uch_custom_format[64];
+ i18n_ustring_copy_ua(uch_custom_format, custom_format);
+ i18n_uchar uch_pattern[64] = {0};
+ int32_t uch_pattern_len;
+ ret = i18n_udatepg_get_best_pattern(dtpg,
+ uch_custom_format,
+ i18n_ustring_get_length(uch_custom_format),
+ uch_pattern,
+ sizeof(uch_pattern),
+ &uch_pattern_len);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ char pattern[64] = {0};
+ i18n_ustring_copy_au_n(pattern, uch_pattern, sizeof(uch_pattern));
+ INF("pattern=%s", pattern);
+
+ i18n_udate_format_h format = NULL;
+ ret = i18n_udate_create(I18N_UDATE_PATTERN,
+ I18N_UDATE_PATTERN,
+ locale,
+ NULL,
+ 0,
+ uch_pattern,
+ i18n_ustring_get_length(uch_pattern),
+ &format);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ i18n_ucalendar_h calendar = NULL;
+ ret = i18n_ucalendar_create(NULL,
+ 0,
+ locale,
+ I18N_UCALENDAR_DEFAULT,
+ &calendar);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ Eina_Array *names = eina_array_new(count);
+
+ int month = 0;
+ int day = 1;
+ for (int i = 0; i < count; ++i)
+ {
+ ret = i18n_ucalendar_set_date_time(calendar,
+ 2012,
+ month,
+ day,
+ 12,
+ 0,
+ 0);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_3);
+
+ i18n_udate udate;
+ ret = i18n_ucalendar_get_milliseconds(calendar, &udate);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_3);
+
+ i18n_uchar uch_result[64] = {0};
+ int32_t uch_result_len;
+ ret = i18n_udate_format_date(format,
+ udate,
+ uch_result,
+ sizeof(uch_result),
+ NULL,
+ &uch_result_len);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_3);
+
+ char result[64] = {0};
+ i18n_ustring_copy_au_n(result, uch_result, sizeof(uch_result));
+ DBG("result=%s", result);
+
+ eina_array_push(names, strdup(result));
+
+ if (ECORDOVA_GLOBALIZATION_DATENAMESITEM_MONTHS == options->item)
+ ++month;
+ else
+ ++day;
+ }
+
+ Ecordova_Globalization_DateNames date_names = {
+ .value = names
+ };
+ eo_do(obj, eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_DATE_NAMES_SUCCESS,
+ &date_names));
+
+ char *name;
+ unsigned int i;
+ Eina_Array_Iterator it;
+ EINA_ARRAY_ITER_NEXT(names, i, name, it)
+ free(name);
+ eina_array_free(names);
+
+ i18n_ucalendar_destroy(calendar);
+ i18n_udate_destroy(format);
+ i18n_udatepg_destroy(dtpg);
+ return;
+
+on_error_3:
+ EINA_ARRAY_ITER_NEXT(names, i, name, it)
+ free(name);
+ eina_array_free(names);
+
+ i18n_ucalendar_destroy(calendar);
+
+on_error_2:
+ i18n_udatepg_destroy(dtpg);
+
+on_error_1:
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_ERROR,
+ &(Ecordova_Globalization_Error){
+ .code = ECORDOVA_GLOBALIZATION_ERRORCODE_UNKNOWN_ERROR,
+ .message = "Unknown error getting date names"
+ }));
+}
+
+static void
+_ecordova_globalization_date_pattern_get(Eo *obj,
+ Ecordova_Globalization_Data *pd EINA_UNUSED,
+ const Ecordova_Globalization_DateTimeOptions *options)
+{
+ DBG("(%p)", obj);
+ const char *locale;
+ int ret = i18n_ulocale_get_default(&locale);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_1);
+
+ i18n_timezone_h timezone = NULL;
+ ret = i18n_timezone_create_default(&timezone);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_1);
+
+ char *timezone_str = NULL;
+ ret = i18n_timezone_get_id(timezone, &timezone_str);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ int32_t utc_offset = 0;
+ ret = i18n_timezone_get_raw_offset(timezone, &utc_offset);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_3);
+
+ int32_t dst_offset = 0;
+ ret = i18n_timezone_get_dst_savings(timezone, &dst_offset);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_3);
+
+ i18n_udate_format_style_e date_style;
+ i18n_udate_format_style_e time_style;
+ _date_time_options_to_style(options, &date_style, &time_style);
+
+ i18n_udate_format_h format = NULL;
+ ret = i18n_udate_create(time_style,
+ date_style,
+ locale,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &format);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_3);
+
+
+ i18n_uchar uch_pattern[64] = {0};
+ int32_t uch_pattern_len = i18n_udate_to_pattern(format,
+ 1,
+ uch_pattern,
+ sizeof(uch_pattern));
+ ret = get_last_result();
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_4);
+ EINA_SAFETY_ON_TRUE_GOTO(uch_pattern_len > (int32_t)sizeof(uch_pattern), on_error_4);
+
+ char pattern[64] = {0};
+ i18n_ustring_copy_au_n(pattern, uch_pattern, sizeof(uch_pattern));
+
+ Ecordova_Globalization_DatePattern date_pattern = {
+ .pattern = pattern,
+ .timezone = timezone_str,
+ .utc_offset = utc_offset / 1000,
+ .dst_offset = dst_offset / 1000
+ };
+ eo_do(obj, eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_DATE_PATTERN_SUCCESS,
+ &date_pattern));
+ i18n_udate_destroy(format);
+ free(timezone_str);
+ i18n_timezone_destroy(timezone);
+ return;
+
+on_error_4:
+ i18n_udate_destroy(format);
+
+on_error_3:
+ free(timezone_str);
+
+on_error_2:
+ i18n_timezone_destroy(timezone);
+
+on_error_1:
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_ERROR,
+ &(Ecordova_Globalization_Error){
+ .code = ECORDOVA_GLOBALIZATION_ERRORCODE_UNKNOWN_ERROR,
+ .message = "Unknown error getting date pattern"
+ }));
+}
+
+static void
+_ecordova_globalization_first_day_of_week_get(Eo *obj,
+ Ecordova_Globalization_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+ const char *locale;
+ int ret = i18n_ulocale_get_default(&locale);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_1);
+
+ i18n_ucalendar_h calendar = NULL;
+ ret = i18n_ucalendar_create(NULL,
+ 0,
+ locale,
+ I18N_UCALENDAR_DEFAULT,
+ &calendar);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_1);
+
+ int32_t value = 0;
+ ret = i18n_ucalendar_get_attribute(calendar,
+ I18N_UCALENDAR_FIRST_DAY_OF_WEEK,
+ &value);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ Ecordova_Globalization_FirstDayOfWeek first_day_of_week = {
+ .value = value
+ };
+ eo_do(obj, eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_FIRST_DAY_OF_WEEK_SUCCESS,
+ &first_day_of_week));
+ i18n_ucalendar_destroy(calendar);
+ return;
+
+on_error_2:
+ i18n_ucalendar_destroy(calendar);
+
+on_error_1:
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_ERROR,
+ &(Ecordova_Globalization_Error){
+ .code = ECORDOVA_GLOBALIZATION_ERRORCODE_UNKNOWN_ERROR,
+ .message = "Unknown error getting first day of week"
+ }));
+}
+
+static void
+_ecordova_globalization_number_pattern_get(Eo *obj,
+ Ecordova_Globalization_Data *pd EINA_UNUSED,
+ const Ecordova_Globalization_NumberPatternOptions *options)
+{
+ DBG("(%p)", obj);
+
+ if (!options)
+ {
+ static const Ecordova_Globalization_NumberPatternOptions default_options = {
+ .type = ECORDOVA_GLOBALIZATION_NUMBERPATTERNTYPE_DECIMAL
+ };
+ options = &default_options;
+ }
+
+ i18n_unumber_format_style_e format_style = I18N_UNUMBER_CURRENCY;
+ switch (options->type)
+ {
+ case ECORDOVA_GLOBALIZATION_NUMBERPATTERNTYPE_DECIMAL:
+ format_style = I18N_UNUMBER_DECIMAL;
+ break;
+ case ECORDOVA_GLOBALIZATION_NUMBERPATTERNTYPE_PERCENT:
+ format_style = I18N_UNUMBER_PERCENT;
+ break;
+ case ECORDOVA_GLOBALIZATION_NUMBERPATTERNTYPE_CURRENCY:
+ format_style = I18N_UNUMBER_CURRENCY;
+ break;
+ }
+
+ i18n_unumber_format_h num_format = NULL;
+ int ret = i18n_unumber_create(format_style,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ &num_format);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_1);
+
+
+ i18n_uchar uch_buffer[64] = {0};
+ int32_t uch_buffer_len;
+ ret = i18n_unumber_get_symbol(num_format,
+ I18N_UNUMBER_PLUS_SIGN_SYMBOL,
+ uch_buffer,
+ sizeof(uch_buffer),
+ &uch_buffer_len);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+ char positive[64] = {0};
+ i18n_ustring_copy_au_n(positive, uch_buffer, sizeof(uch_buffer));
+
+
+ ret = i18n_unumber_get_symbol(num_format,
+ I18N_UNUMBER_MINUS_SIGN_SYMBOL,
+ uch_buffer,
+ sizeof(uch_buffer),
+ &uch_buffer_len);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+ char negative[64] = {0};
+ i18n_ustring_copy_au_n(negative, uch_buffer, sizeof(uch_buffer));
+
+
+ ret = i18n_unumber_get_symbol(num_format,
+ I18N_UNUMBER_DECIMAL_SEPARATOR_SYMBOL,
+ uch_buffer,
+ sizeof(uch_buffer),
+ &uch_buffer_len);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+ char decimal[64] = {0};
+ i18n_ustring_copy_au_n(decimal, uch_buffer, sizeof(uch_buffer));
+
+
+ ret = i18n_unumber_get_symbol(num_format,
+ I18N_UNUMBER_GROUPING_SEPARATOR_SYMBOL,
+ uch_buffer,
+ sizeof(uch_buffer),
+ &uch_buffer_len);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+ char grouping[64] = {0};
+ i18n_ustring_copy_au_n(grouping, uch_buffer, sizeof(uch_buffer));
+
+
+ int32_t len = i18n_unumber_to_pattern(num_format,
+ 1,
+ uch_buffer,
+ sizeof(uch_buffer));
+ ret = get_last_result();
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+ EINA_SAFETY_ON_TRUE_GOTO(len > (int32_t)sizeof(uch_buffer), on_error_2);
+ char pattern[64] = {0};
+ i18n_ustring_copy_au_n(pattern, uch_buffer, sizeof(uch_buffer));
+
+
+ double rounding = i18n_unumber_get_double_attribute(num_format,
+ I18N_UNUMBER_ROUNDING_INCREMENT);
+ ret = get_last_result();
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+ DBG("rounding: %f", rounding);
+
+
+ int32_t fraction = i18n_unumber_get_attribute(num_format,
+ I18N_UNUMBER_MAX_FRACTION_DIGITS);
+ ret = get_last_result();
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+ DBG("fraction: %d", fraction);
+
+ Ecordova_Globalization_NumberPattern number_pattern = {
+ .pattern = pattern,
+ //.symbol =
+ .fraction = fraction,
+ .rounding = rounding,
+ .positive = positive,
+ .negative = negative,
+ .decimal = decimal,
+ .grouping = grouping
+ };
+ eo_do(obj, eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_NUMBER_PATTERN_SUCCESS,
+ &number_pattern));
+
+ i18n_unumber_destroy(num_format);
+ return;
+
+on_error_2:
+ i18n_unumber_destroy(num_format);
+
+on_error_1:
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_ERROR,
+ &(Ecordova_Globalization_Error){
+ .code = ECORDOVA_GLOBALIZATION_ERRORCODE_UNKNOWN_ERROR,
+ .message = "Unknown error getting currency pattern"
+ }));
+}
+
+static void
+_ecordova_globalization_day_light_savings_time_is(Eo *obj,
+ Ecordova_Globalization_Data *pd EINA_UNUSED,
+ time_t date)
+{
+ DBG("(%p)", obj);
+
+ const char *locale;
+ int ret = i18n_ulocale_get_default(&locale);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_1);
+
+ struct tm date_time;
+ localtime_r(&date, &date_time);
+
+ i18n_ucalendar_h calendar = NULL;
+ ret = i18n_ucalendar_create(NULL,
+ 0,
+ locale,
+ I18N_UCALENDAR_DEFAULT,
+ &calendar);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_1);
+
+ ret = i18n_ucalendar_set_date_time(calendar,
+ date_time.tm_year,
+ date_time.tm_mon,
+ date_time.tm_mday,
+ date_time.tm_hour,
+ date_time.tm_min,
+ date_time.tm_sec);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ i18n_ubool value = 0;
+ ret = i18n_ucalendar_is_in_daylight_time(calendar, &value);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ Ecordova_Globalization_DayLightSavingsTime dst = {
+ .dst = !!value
+ };
+ eo_do(obj, eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_DAY_LIGHT_SAVINGS_TIME_SUCCESS,
+ &dst));
+
+ i18n_ucalendar_destroy(calendar);
+ return;
+
+on_error_2:
+ i18n_ucalendar_destroy(calendar);
+
+on_error_1:
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_ERROR,
+ &(Ecordova_Globalization_Error){
+ .code = ECORDOVA_GLOBALIZATION_ERRORCODE_UNKNOWN_ERROR,
+ .message = "Unknown error getting if the date/time is in dst"
+ }));
+}
+
+static void
+_ecordova_globalization_number_to_string(Eo *obj,
+ Ecordova_Globalization_Data *pd EINA_UNUSED,
+ double number,
+ const Ecordova_Globalization_NumberPatternOptions *options)
+{
+ DBG("(%p)", obj);
+
+ if (!options)
+ {
+ static const Ecordova_Globalization_NumberPatternOptions default_options = {
+ .type = ECORDOVA_GLOBALIZATION_NUMBERPATTERNTYPE_DECIMAL
+ };
+ options = &default_options;
+ }
+
+ i18n_unumber_format_style_e format_style = I18N_UNUMBER_CURRENCY;
+ switch (options->type)
+ {
+ case ECORDOVA_GLOBALIZATION_NUMBERPATTERNTYPE_DECIMAL:
+ format_style = I18N_UNUMBER_DECIMAL;
+ break;
+ case ECORDOVA_GLOBALIZATION_NUMBERPATTERNTYPE_PERCENT:
+ format_style = I18N_UNUMBER_PERCENT;
+ break;
+ case ECORDOVA_GLOBALIZATION_NUMBERPATTERNTYPE_CURRENCY:
+ format_style = I18N_UNUMBER_CURRENCY;
+ break;
+ }
+
+ i18n_unumber_format_h num_format = NULL;
+ int ret = i18n_unumber_create(format_style,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ &num_format);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error);
+
+ i18n_uchar uch_buffer[64] = {0};
+ int32_t uch_buffer_len = i18n_unumber_format_double(num_format,
+ number,
+ uch_buffer,
+ sizeof(uch_buffer),
+ NULL);
+ ret = get_last_result();
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, format_error);
+ EINA_SAFETY_ON_TRUE_GOTO(uch_buffer_len > (int32_t)sizeof(uch_buffer), format_error);
+
+ char value[64] = {0};
+ i18n_ustring_copy_au_n(value, uch_buffer, sizeof(uch_buffer));
+
+ Ecordova_Globalization_String gstring = {
+ .value = value
+ };
+ eo_do(obj, eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_NUMBER_TO_STRING_SUCCESS,
+ &gstring));
+
+ i18n_unumber_destroy(num_format);
+ return;
+
+on_error:
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_ERROR,
+ &(Ecordova_Globalization_Error){
+ .code = ECORDOVA_GLOBALIZATION_ERRORCODE_UNKNOWN_ERROR,
+ .message = "Unknown error formatting number"
+ }));
+ return;
+
+format_error:
+ i18n_unumber_destroy(num_format);
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_ERROR,
+ &(Ecordova_Globalization_Error){
+ .code = ECORDOVA_GLOBALIZATION_ERRORCODE_FORMATTING_ERROR,
+ .message = "Format error"
+ }));
+}
+
+static void
+_ecordova_globalization_string_to_date(Eo *obj,
+ Ecordova_Globalization_Data *pd EINA_UNUSED,
+ const char *dateString,
+ const Ecordova_Globalization_DateTimeOptions *options)
+{
+ DBG("(%p)", obj);
+ EINA_SAFETY_ON_NULL_RETURN(dateString);
+
+ i18n_udate_format_style_e date_style;
+ i18n_udate_format_style_e time_style;
+ _date_time_options_to_style(options, &date_style, &time_style);
+
+ const char *locale;
+ int ret = i18n_ulocale_get_default(&locale);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_1);
+
+ i18n_udate_format_h format = NULL;
+ ret = i18n_udate_create(time_style,
+ date_style,
+ locale,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &format);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_1);
+
+
+ i18n_uchar uch_date[64] = {0};
+ i18n_ustring_copy_ua(uch_date, dateString);
+
+ i18n_udate udate;
+ ret = i18n_udate_parse(format,
+ uch_date,
+ -1,
+ NULL,
+ &udate);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, parse_error);
+
+ i18n_ucalendar_h calendar = NULL;
+ ret = i18n_ucalendar_create(NULL,
+ 0,
+ locale,
+ I18N_UCALENDAR_DEFAULT,
+ &calendar);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_1);
+
+ ret = i18n_ucalendar_set_milliseconds(calendar, udate);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ int32_t year = 0;
+ ret = i18n_ucalendar_get(calendar, I18N_UCALENDAR_YEAR, &year);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ int32_t month = 0;
+ ret = i18n_ucalendar_get(calendar, I18N_UCALENDAR_MONTH, &month);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ int32_t day = 0;
+ ret = i18n_ucalendar_get(calendar, I18N_UCALENDAR_DATE, &day);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ int32_t hour = 0;
+ ret = i18n_ucalendar_get(calendar, I18N_UCALENDAR_HOUR_OF_DAY, &hour);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ int32_t minute = 0;
+ ret = i18n_ucalendar_get(calendar, I18N_UCALENDAR_MINUTE, &minute);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ int32_t second = 0;
+ ret = i18n_ucalendar_get(calendar, I18N_UCALENDAR_SECOND, &second);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+ int32_t millisecond = 0;
+ ret = i18n_ucalendar_get(calendar, I18N_UCALENDAR_MILLISECOND, &millisecond);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error_2);
+
+
+ Ecordova_Globalization_DateTime date_time = {
+ .year = year,
+ .month = month,
+ .day = day,
+ .hour = hour,
+ .minute = minute,
+ .second = second,
+ .millisecond = millisecond
+ };
+ eo_do(obj, eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_STRING_TO_DATE_SUCCESS,
+ &date_time));
+
+ i18n_ucalendar_destroy(calendar);
+ i18n_udate_destroy(format);
+ return;
+
+on_error_2:
+ i18n_ucalendar_destroy(calendar);
+
+on_error_1:
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_ERROR,
+ &(Ecordova_Globalization_Error){
+ .code = ECORDOVA_GLOBALIZATION_ERRORCODE_UNKNOWN_ERROR,
+ .message = "Unknown error in string_to_date"
+ }));
+ return;
+
+parse_error:
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_ERROR,
+ &(Ecordova_Globalization_Error){
+ .code = ECORDOVA_GLOBALIZATION_ERRORCODE_PARSING_ERROR,
+ .message = "Parse error"
+ }));
+}
+
+static void
+_ecordova_globalization_string_to_number(Eo *obj,
+ Ecordova_Globalization_Data *pd EINA_UNUSED,
+ const char *string,
+ const Ecordova_Globalization_NumberPatternOptions *options)
+{
+ DBG("(%p)", obj);
+ EINA_SAFETY_ON_NULL_RETURN(string);
+
+ if (!options)
+ {
+ static const Ecordova_Globalization_NumberPatternOptions default_options = {
+ .type = ECORDOVA_GLOBALIZATION_NUMBERPATTERNTYPE_DECIMAL
+ };
+ options = &default_options;
+ }
+
+ i18n_unumber_format_style_e format_style = I18N_UNUMBER_CURRENCY;
+ switch (options->type)
+ {
+ case ECORDOVA_GLOBALIZATION_NUMBERPATTERNTYPE_DECIMAL:
+ format_style = I18N_UNUMBER_DECIMAL;
+ break;
+ case ECORDOVA_GLOBALIZATION_NUMBERPATTERNTYPE_PERCENT:
+ format_style = I18N_UNUMBER_PERCENT;
+ break;
+ case ECORDOVA_GLOBALIZATION_NUMBERPATTERNTYPE_CURRENCY:
+ format_style = I18N_UNUMBER_CURRENCY;
+ break;
+ }
+
+ i18n_uchar uch_number[strlen(string) + 1];
+
+ i18n_unumber_format_h num_format = NULL;
+ int ret = i18n_unumber_create(format_style,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ &num_format);
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, on_error);
+
+
+ i18n_ustring_copy_ua(uch_number, string);
+
+ double value = i18n_unumber_parse_double(num_format,
+ uch_number,
+ -1,
+ NULL);
+ ret = get_last_result();
+ EINA_SAFETY_ON_FALSE_GOTO(I18N_ERROR_NONE == ret, parse_error);
+
+ Ecordova_Globalization_Number gnumber = {
+ .value = value
+ };
+ eo_do(obj, eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_STRING_TO_NUMBER_SUCCESS,
+ &gnumber));
+
+ i18n_unumber_destroy(num_format);
+ return;
+
+on_error:
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_ERROR,
+ &(Ecordova_Globalization_Error){
+ .code = ECORDOVA_GLOBALIZATION_ERRORCODE_UNKNOWN_ERROR,
+ .message = "Unknown error parsing string"
+ }));
+ return;
+
+parse_error:
+ i18n_unumber_destroy(num_format);
+ eo_do(obj,
+ eo_event_callback_call(ECORDOVA_GLOBALIZATION_EVENT_ERROR,
+ &(Ecordova_Globalization_Error){
+ .code = ECORDOVA_GLOBALIZATION_ERRORCODE_PARSING_ERROR,
+ .message = "Parser error"
+ }));
+}
+
+static void
+_date_time_options_to_style(const Ecordova_Globalization_DateTimeOptions *options,
+ i18n_udate_format_style_e *date_style,
+ i18n_udate_format_style_e *time_style)
+{
+ EINA_SAFETY_ON_NULL_RETURN(date_style);
+ EINA_SAFETY_ON_NULL_RETURN(time_style);
+
+ if (!options)
+ {
+ static const Ecordova_Globalization_DateTimeOptions default_options = {
+ .format_length = ECORDOVA_GLOBALIZATION_DATEFORMATLENGTH_SHORT,
+ .selector = ECORDOVA_GLOBALIZATION_DATESELECTOR_DATE_AND_TIME
+ };
+ options = &default_options;
+ };
+
+ *date_style = I18N_UDATE_NONE;
+ *time_style = I18N_UDATE_NONE;
+
+ switch (options->format_length)
+ {
+ case ECORDOVA_GLOBALIZATION_DATEFORMATLENGTH_SHORT:
+ switch (options->selector)
+ {
+ case ECORDOVA_GLOBALIZATION_DATESELECTOR_DATE:
+ *date_style = I18N_UDATE_SHORT;
+ break;
+ case ECORDOVA_GLOBALIZATION_DATESELECTOR_TIME:
+ *time_style = I18N_UDATE_SHORT;
+ break;
+ case ECORDOVA_GLOBALIZATION_DATESELECTOR_DATE_AND_TIME:
+ *date_style = I18N_UDATE_SHORT;
+ *time_style = I18N_UDATE_SHORT;
+ break;
+ }
+ break;
+ case ECORDOVA_GLOBALIZATION_DATEFORMATLENGTH_MEDIUM:
+ switch (options->selector)
+ {
+ case ECORDOVA_GLOBALIZATION_DATESELECTOR_DATE:
+ *date_style = I18N_UDATE_MEDIUM;
+ break;
+ case ECORDOVA_GLOBALIZATION_DATESELECTOR_TIME:
+ *time_style = I18N_UDATE_MEDIUM;
+ break;
+ case ECORDOVA_GLOBALIZATION_DATESELECTOR_DATE_AND_TIME:
+ *date_style = I18N_UDATE_MEDIUM;
+ *time_style = I18N_UDATE_MEDIUM;
+ break;
+ }
+ break;
+ case ECORDOVA_GLOBALIZATION_DATEFORMATLENGTH_LONG:
+ switch (options->selector)
+ {
+ case ECORDOVA_GLOBALIZATION_DATESELECTOR_DATE:
+ *date_style = I18N_UDATE_LONG;
+ break;
+ case ECORDOVA_GLOBALIZATION_DATESELECTOR_TIME:
+ *time_style = I18N_UDATE_LONG;
+ break;
+ case ECORDOVA_GLOBALIZATION_DATESELECTOR_DATE_AND_TIME:
+ *date_style = I18N_UDATE_LONG;
+ *time_style = I18N_UDATE_LONG;
+ break;
+ }
+ break;
+ case ECORDOVA_GLOBALIZATION_DATEFORMATLENGTH_FULL:
+ switch (options->selector)
+ {
+ case ECORDOVA_GLOBALIZATION_DATESELECTOR_DATE:
+ *date_style = I18N_UDATE_FULL;
+ break;
+ case ECORDOVA_GLOBALIZATION_DATESELECTOR_TIME:
+ *time_style = I18N_UDATE_FULL;
+ break;
+ case ECORDOVA_GLOBALIZATION_DATESELECTOR_DATE_AND_TIME:
+ *date_style = I18N_UDATE_FULL;
+ *time_style = I18N_UDATE_FULL;
+ break;
+ }
+ break;
+ };
+}
+
+#include "ecordova_globalization.eo.c"
diff --git a/src/lib/ecordova/ecordova_globalization.eo b/src/lib/ecordova/ecordova_globalization.eo
new file mode 100644
index 0000000000..6c3925ff78
--- /dev/null
+++ b/src/lib/ecordova/ecordova_globalization.eo
@@ -0,0 +1,390 @@
+struct Ecordova_Globalization_Language {
+ value: const(char)*;
+}
+
+struct Ecordova_Globalization_Locale {
+ value: const(char)*;
+}
+
+struct Ecordova_Globalization_String {
+ value: const(char)*;
+}
+
+enum Ecordova_Globalization_DateFormatLength {
+ SHORT,
+ MEDIUM,
+ LONG,
+ FULL
+}
+
+enum Ecordova_Globalization_DateSelector {
+ DATE,
+ TIME,
+ DATE_AND_TIME
+}
+
+struct Ecordova_Globalization_DateTimeOptions {
+ format_length: int;
+ selector: int;
+}
+
+enum Ecordova_Globalization_ErrorCode {
+ [[Represents a error from the Globalization API.]]
+ UNKNOWN_ERROR = 0,
+ FORMATTING_ERROR = 1,
+ PARSING_ERROR = 2,
+ PATTERN_ERROR = 3
+}
+
+struct Ecordova_Globalization_Error {
+ [[An object representing a error from the Globalization API.]]
+
+ code: int;
+ [[One of the codes representing the error type]]
+
+ message: const(char)*;
+ [[A text message that includes the error's explanation and/or details]]
+}
+
+struct Ecordova_Globalization_CurrencyPattern {
+ pattern: const(char)*;
+ [[The currency pattern to format and parse currency values. The patterns
+ follow Unicode Technical Standard #35.]]
+
+ code: const(char)*;
+ [[The ISO 4217 currency code for the pattern.]]
+
+ fraction: int;
+ [[The number of fractional digits to use when parsing and formatting
+ currency.]]
+
+ rounding: double;
+ [[The rounding increment to use when parsing and formatting.]]
+
+ decimal: const(char)*;
+ [[The decimal symbol to use for parsing and formatting.]]
+
+ grouping: const(char)*;
+ [[The grouping symbol to use for parsing and formatting.]]
+}
+
+enum Ecordova_Globalization_DateNamesType {
+ NARROW,
+ WIDE
+}
+
+enum Ecordova_Globalization_DateNamesItem {
+ MONTHS,
+ DAYS
+}
+
+struct Ecordova_Globalization_DateNamesOptions {
+ type: int;
+ item: int;
+}
+
+struct Ecordova_Globalization_DateNames {
+ value: array<char*>*;
+}
+
+struct Ecordova_Globalization_DatePattern {
+ pattern: const(char)*;
+ [[The date and time pattern to format and parse dates. The patterns follow
+ Unicode Technical Standard #35.]]
+
+ timezone: const(char)*;
+ [[The abbreviated name of the time zone on the client.]]
+
+ utc_offset: int;
+ [[The current difference in seconds between the client's time zone and
+ coordinated universal time.]]
+
+ dst_offset: int;
+ [[The current daylight saving time offset in seconds between the client's
+ non-daylight saving's time zone and the client's daylight saving's
+ time zone.]]
+}
+
+struct Ecordova_Globalization_FirstDayOfWeek {
+ value: int;
+ [[The days of the week are numbered starting from 1, where 1 is assumed to
+ be Sunday.]]
+}
+
+struct Ecordova_Globalization_NumberPattern {
+ pattern: const(char)*;
+ [[The number pattern to format and parse numbers. The patterns follow
+ Unicode Technical Standard #35.]]
+
+ symbol: const(char)*;
+ [[The symbol to use when formatting and parsing, such as a percent or
+ currency symbol.]]
+
+ fraction: int;
+ [[The number of fractional digits to use when parsing and formatting
+ numbers.]]
+
+ rounding: double;
+ [[The rounding increment to use when parsing and formatting.]]
+
+ positive: const(char)*;
+ [[The symbol to use for positive numbers when parsing and formatting.]]
+
+ negative: const(char)*;
+ [[The symbol to use for negative numbers when parsing and formatting.]]
+
+ decimal: const(char)*;
+ [[The decimal symbol to use for parsing and formatting.]]
+
+ grouping: const(char)*;
+ [[The grouping symbol to use for parsing and formatting.]]
+}
+
+enum Ecordova_Globalization_NumberPatternType {
+ DECIMAL,
+ PERCENT,
+ CURRENCY
+}
+
+struct Ecordova_Globalization_NumberPatternOptions {
+ type: int;
+}
+
+struct Ecordova_Globalization_DayLightSavingsTime {
+ dst: bool;
+ [[A true value indicates that daylight savings time is in effect for the
+ given date, and false indicates that it is not.]]
+}
+
+struct Ecordova_Globalization_DateTime {
+ year: int;
+ [[The four digit year.]]
+
+ month: int;
+ [[The month from (0-11).]]
+
+ day: int;
+ [[The day from (1-31).]]
+
+ hour: int;
+ [[The hour from (0-23).]]
+
+ minute: int;
+ [[The minute from (0-59).]]
+
+ second: int;
+ [[The second from (0-59).]]
+
+ millisecond: int;
+ [[The milliseconds (from 0-999), not available on all platforms.]]
+}
+
+struct Ecordova_Globalization_Number {
+ value: double;
+}
+
+class Ecordova.Globalization (Eo.Base) {
+ [[Ecordova Globalization Plugin
+ Plugin ID: org.apache.cordova.globalization
+ http://plugins.cordova.io/#/package/org.apache.cordova.globalization
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_Globalization constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ }
+ preferred_language_get {
+ [[Get the BCP 47 language tag for the client's current language.
+
+ Returns the BCP-47 compliant language identifier tag to the
+ successCallback with a properties object as a parameter. That
+ object should have a value property with a String value.
+
+ If there is an error getting the language, then the
+ errorCallback executes with a GlobalizationError object as a
+ parameter. The error's expected code is
+ GlobalizationError.UNKNOWN_ERROR.]]
+ }
+ locale_name_get {
+ [[Returns the BCP 47 compliant tag for the client's current locale
+ setting.
+
+ Returns the BCP 47 compliant locale identifier string to the
+ successCallback with a properties object as a parameter. That
+ object should have a value property with a String value. The
+ locale tag will consist of a two-letter lower case language
+ code, two-letter upper case country code, and (unspecified)
+ variant code, separated by a hyphen.
+
+ If there is an error getting the locale, then the errorCallback
+ executes with a GlobalizationError object as a parameter. The
+ error's expected code is GlobalizationError.UNKNOWN_ERROR.]]
+ }
+ date_to_string {
+ [[Returns a date formatted as a string according to the client's
+ locale and timezone.
+
+ Returns the formatted date String via a value property
+ accessible from the object passed as a parameter to the
+ successCallback.
+
+ If there is an error formatting the date, then the errorCallback
+ executes with a GlobalizationError object as a parameter.
+ The error's expected code is
+ GlobalizationError.FORMATTING_ERROR.]]
+ params {
+ date: time;
+ [[The date to convert to string]]
+
+ options: const(Ecordova_Globalization_DateTimeOptions)*;
+ [[The options parameter is optional, and its default values
+ are: {format_length:'short', selector:'date and time'}]]
+ }
+ }
+ currency_pattern_get {
+ [[Returns a pattern string to format and parse currency values
+ according to the client's user preferences and ISO 4217 currency
+ code.]]
+ params {
+ currency_code: const(char)*;
+ [[The inbound currency_code parameter should be a String of one
+ of the ISO 4217 currency codes, for example 'USD'.]]
+ }
+ }
+ date_names_get {
+ [[Returns the array of names to the successCallback with a
+ properties object as a parameter. That object contains a value
+ property with an Array of String values. The array features
+ names starting from either the first month in the year or the
+ first day of the week, depending on the option selected.
+
+ If there is an error obtaining the names, then the errorCallback
+ executes with a GlobalizationError object as a parameter. The
+ error's expected code is GlobalizationError.UNKNOWN_ERROR.]]
+ params {
+ options: const(Ecordova_Globalization_DateNamesOptions)*;
+ [[The options parameter is optional, and its default values
+ are: {type:'wide', item:'months'}]]
+ }
+ }
+ date_pattern_get {
+ [[Returns a pattern string to format and parse dates according to
+ the client's user preferences.
+
+ If there is an error obtaining the pattern, the errorCallback
+ executes with a GlobalizationError object as a parameter. The
+ error's expected code is GlobalizationError.PATTERN_ERROR.]]
+ params {
+ options: const(Ecordova_Globalization_DateTimeOptions)*;
+ [[The options parameter is optional, and defaults
+ to: {format_length:'short', selector:'date and time'}]]
+ }
+ }
+ first_day_of_week_get {
+ [[Returns the first day of the week according to the client's user
+ preferences and calendar.
+
+ The days of the week are numbered starting from 1, where 1 is
+ assumed to be Sunday. Returns the day to the successCallback
+ with a properties object as a parameter. That object should have
+ a value property with a Number value.
+
+ If there is an error obtaining the pattern, then the
+ errorCallback executes with a GlobalizationError object as a
+ parameter. The error's expected code is
+ GlobalizationError.UNKNOWN_ERROR.]]
+ }
+ number_pattern_get {
+ [[Returns a pattern string to format and parse numbers according
+ to the client's user preferences.]]
+ params {
+ options: const(Ecordova_Globalization_NumberPatternOptions)*;
+ [[The options parameter is optional, and default values
+ are: {type:'decimal'}]]
+ }
+ }
+ day_light_savings_time_is {
+ [[Indicates whether daylight savings time is in effect for a given
+ date using the client's time zone and calendar.
+
+ Indicates whether or not daylight savings time is in effect to
+ the successCallback with a properties object as a parameter.
+ That object should have a dst property with a Boolean value. A
+ true value indicates that daylight savings time is in effect for
+ the given date, and false indicates that it is not.
+
+ If there is an error reading the date, then the errorCallback
+ executes. The error's expected code is
+ GlobalizationError.UNKNOWN_ERROR.]]
+ params {
+ date: time;
+ }
+ }
+ number_to_string {
+ [[Returns a number formatted as a string according to the client's
+ user preferences.]]
+ params {
+ number: double;
+
+ options: const(Ecordova_Globalization_NumberPatternOptions)*;
+ [[The options parameter is optional, and its default values
+ are: {type:'decimal'}]]
+ }
+ }
+ string_to_date {
+ [[Parses a date formatted as a string, according to the client's
+ user preferences and calendar using the time zone of the client,
+ and returns the corresponding date object.]]
+ params {
+ dateString: const(char)*;
+ options: const(Ecordova_Globalization_DateTimeOptions)*;
+ }
+ }
+ string_to_number {
+ [[Parses a number formatted as a string according to the client's
+ user preferences and returns the corresponding number.
+
+ Returns the number to the successCallback with a properties
+ object as a parameter. That object should have a value property
+ with a Number value.
+
+ If there is an error parsing the number string, then the
+ errorCallback executes with a GlobalizationError object as a
+ parameter. The error's expected code is
+ GlobalizationError.PARSING_ERROR.]]
+ params {
+ string: const(char)*;
+
+ options: const(Ecordova_Globalization_NumberPatternOptions)*;
+ [[The options parameter is optional, and defaults to the
+ following values: {type:'decimal'}]]
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ preferred,language,success: const(Ecordova_Globalization_Language)*;
+ locale,name,success: const(Ecordova_Globalization_Locale)*;
+ date,to,string,success: const(Ecordova_Globalization_String)*;
+ currency,pattern,success: const(Ecordova_Globalization_CurrencyPattern)*;
+ date,names,success: const(Ecordova_Globalization_DateNames)*;
+ date,pattern,success: const(Ecordova_Globalization_DatePattern)*;
+ first,day,of,week,success: const(Ecordova_Globalization_FirstDayOfWeek)*;
+ number,pattern,success: const(Ecordova_Globalization_NumberPattern)*;
+ day,light,savings,time,success: const(Ecordova_Globalization_DayLightSavingsTime)*;
+ number,to,string,success: const(Ecordova_Globalization_String)*;
+ string,to,date,success: const(Ecordova_Globalization_DateTime)*;
+ string,to,number,success: const(Ecordova_Globalization_Number)*;
+ error: Ecordova_Globalization_ErrorCode;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_globalization_private.h b/src/lib/ecordova/ecordova_globalization_private.h
new file mode 100644
index 0000000000..1df1384a87
--- /dev/null
+++ b/src/lib/ecordova/ecordova_globalization_private.h
@@ -0,0 +1,16 @@
+#ifndef _ECORDOVA_GLOBALIZATION_PRIVATE_H
+#define _ECORDOVA_GLOBALIZATION_PRIVATE_H
+
+#include "ecordova_private.h"
+
+typedef struct _Ecordova_Globalization_Data Ecordova_Globalization_Data;
+
+/**
+ * Ecordova.Globalization private data
+ */
+struct _Ecordova_Globalization_Data
+{
+ Eo *obj;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_inappbrowser.c b/src/lib/ecordova/ecordova_inappbrowser.c
new file mode 100644
index 0000000000..4d6cc1686e
--- /dev/null
+++ b/src/lib/ecordova/ecordova_inappbrowser.c
@@ -0,0 +1,78 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_inappbrowser_private.h"
+
+#define MY_CLASS ECORDOVA_INAPPBROWSER_CLASS
+#define MY_CLASS_NAME "Ecordova_InAppBrowser"
+
+static Eo_Base *
+_ecordova_inappbrowser_eo_base_constructor(Eo *obj,
+ Ecordova_InAppBrowser_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_inappbrowser_constructor(Eo *obj EINA_UNUSED,
+ Ecordova_InAppBrowser_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+}
+
+static void
+_ecordova_inappbrowser_eo_base_destructor(Eo *obj,
+ Ecordova_InAppBrowser_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static Ecordova_InAppBrowser*
+_ecordova_inappbrowser_open(Eo *obj EINA_UNUSED,
+ void *pd EINA_UNUSED,
+ const char *url EINA_UNUSED,
+ const char *target EINA_UNUSED,
+ const Eina_Hash *options EINA_UNUSED)
+{
+ ERR("Not implemented.");
+ return NULL;
+}
+
+static void
+_ecordova_inappbrowser_close(Eo *obj EINA_UNUSED,
+ Ecordova_InAppBrowser_Data *pd EINA_UNUSED)
+{
+ ERR("Not implemented.");
+}
+
+static void
+_ecordova_inappbrowser_show(Eo *obj EINA_UNUSED,
+ Ecordova_InAppBrowser_Data *pd EINA_UNUSED)
+{
+ ERR("Not implemented.");
+}
+
+static void
+_ecordova_inappbrowser_script_execute(Eo *obj EINA_UNUSED,
+ Ecordova_InAppBrowser_Data *pd EINA_UNUSED,
+ const Ecordova_InAppBrowser_InjectDetails *injectDetails EINA_UNUSED)
+{
+ ERR("Not implemented.");
+}
+
+static void
+_ecordova_inappbrowser_css_insert(Eo *obj EINA_UNUSED,
+ Ecordova_InAppBrowser_Data *pd EINA_UNUSED,
+ const Ecordova_InAppBrowser_InjectDetails *injectDetails EINA_UNUSED)
+{
+ ERR("Not implemented.");
+}
+
+#include "ecordova_inappbrowser.eo.c"
diff --git a/src/lib/ecordova/ecordova_inappbrowser.eo b/src/lib/ecordova/ecordova_inappbrowser.eo
new file mode 100644
index 0000000000..d2e16da78f
--- /dev/null
+++ b/src/lib/ecordova/ecordova_inappbrowser.eo
@@ -0,0 +1,89 @@
+struct Ecordova_InAppBrowser_InjectDetails {
+ file: const(char)*; [[URL of the script/stylesheet to inject.]]
+ code: const(char)*; [[Text of the script/stylesheet to inject.]]
+}
+
+struct Ecordova_InAppBrowser_EventProperties {
+ type: const(char)*; [[the eventname, either loadstart, loadstop, loaderror, or exit.]]
+ url: const(char)*; [[the URL that was loaded.]]
+ code: const(char)*; [[the error code, only in the case of loaderror.]]
+ message: const(char)*; [[the error message, only in the case of loaderror.]]
+}
+
+class Ecordova.InAppBrowser (Eo.Base) {
+ [[Ecordova InAppBrowser Plugin
+ Plugin ID: org.apache.cordova.inappbrowser
+ http://plugins.cordova.io/#/package/org.apache.cordova.inappbrowser
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_InAppBrowser constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ }
+ open @class {
+ params {
+ url: const(char)*;
+ [[The URL to load. Call encodeURI() on this if the URL
+ contains Unicode characters.]]
+
+ target: const(char)*;
+ [[The target in which to load the URL, an optional parameter
+ that defaults to _self.]]
+
+ options: const(hash<char*,char*>)*;
+ [[Options for the InAppBrowser. Optional, defaulting
+ to: location=yes.]]
+
+ }
+ return: Ecordova.InAppBrowser*;
+ }
+ close {
+ [[Closes the InAppBrowser window.]]
+ }
+ show {
+ [[Displays an InAppBrowser window that was opened hidden. Calling
+ this has no effect if the InAppBrowser was already visible.]]
+ }
+ script_execute {
+ [[Injects JavaScript code into the InAppBrowser window]]
+ params {
+ injectDetails: const(Ecordova_InAppBrowser_InjectDetails)*;
+ [[details of the script to run, specifying either a file or
+ code key.]]
+ }
+ }
+ css_insert {
+ [[Injects CSS into the InAppBrowser window.]]
+ params {
+ injectDetails: const(Ecordova_InAppBrowser_InjectDetails)*;
+ [[details of the script to run, specifying either a file or
+ code key.]]
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ load,start: const(Ecordova_InAppBrowser_EventProperties)*;
+ load,stop: const(Ecordova_InAppBrowser_EventProperties)*;
+ load,error: const(Ecordova_InAppBrowser_EventProperties)*;
+ exit: const(Ecordova_InAppBrowser_EventProperties)*;
+
+ script,executed;
+ [[If the injected script is of type code, the callback executes with a
+ single parameter, which is the return value of the script, wrapped
+ in an Array. For multi-line scripts, this is the return value of the
+ last statement, or the last expression evaluated.]]
+
+ css,injected; [[executes after the CSS is injected.]]
+ }
+}
diff --git a/src/lib/ecordova/ecordova_inappbrowser_private.h b/src/lib/ecordova/ecordova_inappbrowser_private.h
new file mode 100644
index 0000000000..4526e8773b
--- /dev/null
+++ b/src/lib/ecordova/ecordova_inappbrowser_private.h
@@ -0,0 +1,16 @@
+#ifndef _ECORDOVA_INAPPBROWSER_PRIVATE_H
+#define _ECORDOVA_INAPPBROWSER_PRIVATE_H
+
+#include "ecordova_private.h"
+
+typedef struct _Ecordova_InAppBrowser_Data Ecordova_InAppBrowser_Data;
+
+/**
+ * Ecordova.InAppBrowser private data
+ */
+struct _Ecordova_InAppBrowser_Data
+{
+ Eo *obj;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_main.c b/src/lib/ecordova/ecordova_main.c
new file mode 100644
index 0000000000..701e953dce
--- /dev/null
+++ b/src/lib/ecordova/ecordova_main.c
@@ -0,0 +1,98 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_private.h"
+#include "ecordova_systeminfo.eo.h"
+
+#include <Ecore_File.h>
+
+static int _ecordova_init_count = 0;
+int _ecordova_log_dom = -1;
+Eo* _ecordova_systeminfo = NULL;
+
+EAPI int
+ecordova_init(void)
+{
+ if (_ecordova_init_count++ > 0)
+ return _ecordova_init_count;
+
+ if (!eina_init())
+ {
+ fputs("Ecordova: Unable to initialize eina\n", stderr);
+ return 0;
+ }
+
+ _ecordova_log_dom = eina_log_domain_register("ecordova", EINA_COLOR_CYAN);
+ if (_ecordova_log_dom < 0)
+ {
+ EINA_LOG_ERR("Unable to create an 'ecordova' log domain");
+ goto on_error_1;
+ }
+
+ if (!ecore_init())
+ {
+ ERR("Unable to initialize ecore");
+ goto on_error_2;
+ }
+
+ if (!ecore_file_init())
+ {
+ ERR("Unable to initialize ecore_file");
+ goto on_error_3;
+ }
+
+ if (!eio_init())
+ {
+ ERR("Unable to initialize eio");
+ goto on_error_4;
+ }
+
+ _ecordova_systeminfo = eo_add(ECORDOVA_SYSTEMINFO_CLASS, NULL,
+ ecordova_systeminfo_constructor());
+ if (!_ecordova_systeminfo)
+ {
+ ERR("Unable to initialize systeminfo service");
+ goto on_error_4;
+ }
+
+ return _ecordova_init_count;
+
+on_error_4:
+ ecore_file_shutdown();
+
+on_error_3:
+ ecore_shutdown();
+
+on_error_2:
+ eina_log_domain_unregister(_ecordova_log_dom);
+
+on_error_1:
+ _ecordova_log_dom = -1;
+ eina_shutdown();
+ return 0;
+}
+
+EAPI int
+ecordova_shutdown(void)
+{
+ if (_ecordova_init_count <= 0)
+ {
+ ERR("Init count not greater than 0 in shutdown.");
+ _ecordova_init_count = 0;
+ return 0;
+ }
+
+ if (--_ecordova_init_count)
+ return _ecordova_init_count;
+
+ eo_unref(_ecordova_systeminfo);
+ eio_shutdown();
+ ecore_file_shutdown();
+ ecore_shutdown();
+ eina_log_domain_unregister(_ecordova_log_dom);
+ _ecordova_log_dom = -1;
+ eina_shutdown();
+ return 0;
+}
+
diff --git a/src/lib/ecordova/ecordova_media.c b/src/lib/ecordova/ecordova_media.c
new file mode 100644
index 0000000000..926a2cad49
--- /dev/null
+++ b/src/lib/ecordova/ecordova_media.c
@@ -0,0 +1,531 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_media_private.h"
+
+#define MY_CLASS ECORDOVA_MEDIA_CLASS
+#define MY_CLASS_NAME "Ecordova_Media"
+
+typedef void(* Action_Cb)(Ecordova_Media_Data *, void *);
+
+typedef struct {
+ Action_Cb callback;
+ void *data;
+} Action;
+
+static void _completed_cb(void *);
+static void _error_cb(int, void *);
+static void _prepared_cb(void *);
+static void _set_position_cb(void *);
+static void _execute(Ecordova_Media_Data *, Action_Cb, void *);
+static void _pause_action(Ecordova_Media_Data *, void *);
+static void _start_action(Ecordova_Media_Data *, void *);
+static void _stop_action(Ecordova_Media_Data *, void *);
+static void _get_position_action(Ecordova_Media_Data *, void *);
+static void _set_position_action(Ecordova_Media_Data *, void *);
+static void _set_volume_action(Ecordova_Media_Data *, void *);
+static void _update_status(Ecordova_Media_Data *);
+static void _release(Ecordova_Media_Data *);
+static void _state_changed_cb(recorder_state_e, recorder_state_e, bool, void *);
+static void _start_record(Ecordova_Media_Data *);
+
+static Eo_Base *
+_ecordova_media_eo_base_constructor(Eo *obj, Ecordova_Media_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->player = NULL;
+ pd->recorder = NULL;
+ pd->status = ECORDOVA_MEDIA_STATUS_MEDIA_NONE;
+ pd->pending = NULL;
+ pd->record_pending = false;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_media_constructor(Eo *obj,
+ Ecordova_Media_Data *pd,
+ const char *src)
+{
+ DBG("(%p)", obj);
+ EINA_SAFETY_ON_NULL_RETURN(src);
+
+ int ret = player_create(&pd->player);
+ EINA_SAFETY_ON_FALSE_RETURN(PLAYER_ERROR_NONE == ret);
+
+ ret = recorder_create_audiorecorder(&pd->recorder);
+ EINA_SAFETY_ON_FALSE_RETURN(RECORDER_ERROR_NONE == ret);
+
+ ret = player_set_uri(pd->player, src);
+ if (PLAYER_ERROR_NONE != ret)
+ {
+ ERR("Error setting source media: %s", src);
+ _release(pd);
+ return;
+ }
+
+ ret = player_set_completed_cb(pd->player,
+ _completed_cb,
+ pd);
+ if (PLAYER_ERROR_NONE != ret)
+ {
+ ERR("Error setting completed callback: %d", ret);
+ _release(pd);
+ return;
+ }
+
+ ret = player_set_error_cb(pd->player,
+ _error_cb,
+ pd);
+ if (PLAYER_ERROR_NONE != ret)
+ {
+ ERR("Error setting completed callback: %d", ret);
+ _release(pd);
+ return;
+ }
+
+ ret = recorder_set_state_changed_cb(pd->recorder,
+ _state_changed_cb,
+ pd);
+ if (RECORDER_ERROR_NONE != ret)
+ {
+ ERR("Error setting recorder state changed callback: %d", ret);
+ _release(pd);
+ return;
+ }
+
+ ret = recorder_set_audio_encoder(pd->recorder, RECORDER_AUDIO_CODEC_AAC);
+ if (RECORDER_ERROR_NONE != ret)
+ {
+ ERR("Error setting audio encoder: %d", ret);
+ _release(pd);
+ return;
+ }
+
+ ret = recorder_attr_set_audio_samplerate(pd->recorder, 44100);
+ if (RECORDER_ERROR_NONE != ret)
+ {
+ ERR("Error setting audio sample rate: %d", ret);
+ _release(pd);
+ return;
+ }
+
+ ret = recorder_set_file_format(pd->recorder, RECORDER_FILE_FORMAT_3GP);
+ if (RECORDER_ERROR_NONE != ret)
+ {
+ ERR("Error setting file format for audio encoder: %d", ret);
+ _release(pd);
+ return;
+ }
+
+ ret = recorder_attr_set_audio_encoder_bitrate(pd->recorder, 28800);
+ if (RECORDER_ERROR_NONE != ret)
+ {
+ ERR("Error setting audio encoder bitrate: %d", ret);
+ _release(pd);
+ return;
+ }
+
+ ret = recorder_set_filename(pd->recorder, src);
+ if (RECORDER_ERROR_NONE != ret)
+ {
+ ERR("Error setting recorder filename: %d", ret);
+ _release(pd);
+ return;
+ }
+}
+
+static void
+_ecordova_media_eo_base_destructor(Eo *obj, Ecordova_Media_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ _release(pd);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_media_current_position_get(Eo *obj, Ecordova_Media_Data *pd)
+{
+ DBG("(%p)", obj);
+ _execute(pd, _get_position_action, NULL);
+}
+
+static int
+_ecordova_media_duration_get(Eo *obj EINA_UNUSED, Ecordova_Media_Data *pd)
+{
+ int duration = -1;
+
+ int ret = player_get_duration(pd->player, &duration);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(PLAYER_ERROR_NONE == ret, -1);
+
+ return duration / 1000;
+}
+
+static void
+_ecordova_media_pause(Eo *obj, Ecordova_Media_Data *pd)
+{
+ DBG("(%p)", obj);
+ _execute(pd, _pause_action, NULL);
+}
+
+static void
+_ecordova_media_play(Eo *obj, Ecordova_Media_Data *pd)
+{
+ DBG("(%p)", obj);
+ _execute(pd, _start_action, NULL);
+}
+
+static void
+_ecordova_media_release(Eo *obj, Ecordova_Media_Data *pd)
+{
+ DBG("(%p)", obj);
+ _release(pd);
+}
+
+static void
+_ecordova_media_seek(Eo *obj, Ecordova_Media_Data *pd, int milliseconds)
+{
+ DBG("(%p)", obj);
+ int *data = malloc(sizeof(milliseconds));
+ *data = milliseconds;
+ _execute(pd, _set_position_action, data);
+}
+
+static void
+_ecordova_media_volume_set(Eo *obj, Ecordova_Media_Data *pd, double volume)
+{
+ DBG("(%p)", obj);
+ double *data = malloc(sizeof(volume));
+ *data = volume;
+ _execute(pd, _set_volume_action, data);
+}
+
+static void
+_ecordova_media_record_start(Eo *obj, Ecordova_Media_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ recorder_state_e state = RECORDER_STATE_NONE;
+ int ret = recorder_get_state(pd->recorder, &state);
+ EINA_SAFETY_ON_FALSE_RETURN(RECORDER_ERROR_NONE == ret);
+
+ switch (state)
+ {
+ case RECORDER_STATE_NONE:
+ case RECORDER_STATE_CREATED:
+ ret = recorder_prepare(pd->recorder);
+ EINA_SAFETY_ON_FALSE_RETURN(RECORDER_ERROR_NONE == ret);
+ pd->record_pending = true;
+ return;
+ case RECORDER_STATE_READY:
+ if (pd->record_pending)
+ {
+ ERR("%s", "The recorder has already been started and is pending.");
+ return;
+ }
+ _start_record(pd);
+ return;
+ case RECORDER_STATE_RECORDING:
+ ERR("%s", "The recorder is already recording.");
+ return;
+ case RECORDER_STATE_PAUSED:
+ ERR("%s", "Unreachable!");
+ return;
+ }
+}
+
+static void
+_ecordova_media_stop(Eo *obj, Ecordova_Media_Data *pd)
+{
+ DBG("(%p)", obj);
+ _execute(pd, _stop_action, NULL);
+}
+
+static void
+_ecordova_media_record_stop(Eo *obj, Ecordova_Media_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ recorder_state_e state = RECORDER_STATE_NONE;
+ int ret = recorder_get_state(pd->recorder, &state);
+ EINA_SAFETY_ON_FALSE_RETURN(RECORDER_ERROR_NONE == ret);
+
+ switch (state)
+ {
+ case RECORDER_STATE_NONE:
+ case RECORDER_STATE_CREATED:
+ case RECORDER_STATE_READY:
+ ERR("%s", "The recorder is not recording.");
+ return;
+ case RECORDER_STATE_RECORDING:
+ ret = recorder_commit(pd->recorder);
+ return;
+ case RECORDER_STATE_PAUSED:
+ ERR("%s", "Unreachable!");
+ return;
+ }
+}
+
+static void
+_completed_cb(void *data)
+{
+ Ecordova_Media_Data *pd = data;
+ DBG("(%p)", pd->obj);
+
+ // TODO: Check what thread this callback is running to make sure it's on the main thread
+
+ _update_status(pd);
+
+ eo_do(pd->obj, eo_event_callback_call(ECORDOVA_MEDIA_EVENT_MEDIA_SUCCESS, NULL));
+}
+
+static void
+_error_cb(int error EINA_UNUSED, void *data)
+{
+ Ecordova_Media_Data *pd = data;
+ DBG("(%p)", pd->obj);
+
+ // TODO: ¿ check error ?
+
+ // TODO: Check what thread this callback is running to make sure it's on the main thread
+
+ _update_status(pd);
+
+ eo_do(pd->obj, eo_event_callback_call(ECORDOVA_MEDIA_EVENT_MEDIA_ERROR, NULL));
+}
+
+static void
+_prepared_cb(void *data)
+{
+ Ecordova_Media_Data *pd = data;
+ DBG("(%p)", pd->obj);
+
+ Action *action;
+ EINA_LIST_FREE(pd->pending, action)
+ {
+ action->callback(pd, action->data);
+ free(action->data);
+ free(action);
+ }
+
+}
+
+static void
+_set_position_cb(void *data)
+{
+ Ecordova_Media_Data *pd = data;
+ DBG("(%p)", pd->obj);
+
+ // TODO: Check what thread this callback is running to make sure it's on the main thread
+
+ eo_do(pd->obj, eo_event_callback_call(ECORDOVA_MEDIA_EVENT_MEDIA_SUCCESS, NULL));
+}
+
+static void
+_execute(Ecordova_Media_Data *pd, Action_Cb action_cb, void *data)
+{
+ DBG("(%p)", pd->obj);
+
+ switch (pd->status)
+ {
+ case ECORDOVA_MEDIA_STATUS_MEDIA_NONE:
+ {
+ int ret = player_prepare_async(pd->player,
+ _prepared_cb,
+ pd);
+ EINA_SAFETY_ON_FALSE_RETURN(PLAYER_ERROR_NONE == ret);
+
+ pd->status = ECORDOVA_MEDIA_STATUS_MEDIA_STARTING;
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_MEDIA_EVENT_MEDIA_STATUS, &pd->status));
+ // fall-through
+ }
+ case ECORDOVA_MEDIA_STATUS_MEDIA_STARTING:
+ {
+ Action *action = malloc(sizeof(Action));
+ action->callback = action_cb;
+ action->data = data;
+
+ pd->pending = eina_list_append(pd->pending, action);
+ return;
+ }
+ default:
+ action_cb(pd, data);
+ }
+}
+
+static void
+_pause_action(Ecordova_Media_Data *pd, void *data EINA_UNUSED)
+{
+ DBG("(%p)", pd->obj);
+
+ int ret = player_pause(pd->player);
+ EINA_SAFETY_ON_FALSE_RETURN(PLAYER_ERROR_NONE == ret);
+
+ _update_status(pd);
+}
+
+static void
+_stop_action(Ecordova_Media_Data *pd, void *data EINA_UNUSED)
+{
+ DBG("(%p)", pd->obj);
+
+ int ret = player_stop(pd->player);
+ EINA_SAFETY_ON_FALSE_RETURN(PLAYER_ERROR_NONE == ret);
+
+ _update_status(pd);
+}
+
+static void
+_start_action(Ecordova_Media_Data *pd, void *data EINA_UNUSED)
+{
+ DBG("(%p)", pd->obj);
+
+ int ret = player_stop(pd->player);
+ EINA_SAFETY_ON_FALSE_RETURN(PLAYER_ERROR_NONE == ret);
+
+ _update_status(pd);
+}
+
+static void
+_get_position_action(Ecordova_Media_Data *pd, void *data EINA_UNUSED)
+{
+ DBG("(%p)", pd->obj);
+
+ int position = 0;
+ int ret = player_get_play_position(pd->player, &position);
+ EINA_SAFETY_ON_FALSE_RETURN(PLAYER_ERROR_NONE == ret);
+
+ position /= 1000;
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_MEDIA_EVENT_MEDIA_POSITION, &position));
+}
+
+static void
+_set_position_action(Ecordova_Media_Data *pd, void *data)
+{
+ DBG("(%p)", pd->obj);
+
+ int *position = data;
+ int ret = player_set_play_position(pd->player,
+ *position,
+ false,
+ _set_position_cb,
+ pd);
+ free(position);
+ EINA_SAFETY_ON_FALSE_RETURN(PLAYER_ERROR_NONE == ret);
+}
+
+static void
+_set_volume_action(Ecordova_Media_Data *pd, void *data)
+{
+ DBG("(%p)", pd->obj);
+
+ double *volume = data;
+ int ret = player_set_volume(pd->player, *volume, *volume);
+ free(volume);
+ EINA_SAFETY_ON_FALSE_RETURN(PLAYER_ERROR_NONE == ret);
+ eo_do(pd->obj, eo_event_callback_call(ECORDOVA_MEDIA_EVENT_MEDIA_SUCCESS, NULL));
+}
+
+static void
+_update_status(Ecordova_Media_Data *pd)
+{
+ player_state_e state = PLAYER_STATE_NONE;
+
+ int ret = player_get_state(pd->player, &state);
+ EINA_SAFETY_ON_FALSE_RETURN(PLAYER_ERROR_NONE == ret);
+
+ Ecordova_Media_Status new_status = ECORDOVA_MEDIA_STATUS_MEDIA_NONE;
+ switch (state)
+ {
+ case PLAYER_STATE_NONE:
+ new_status = ECORDOVA_MEDIA_STATUS_MEDIA_NONE;
+ break;
+ case PLAYER_STATE_IDLE:
+ new_status = ECORDOVA_MEDIA_STATUS_MEDIA_STARTING;
+ break;
+ case PLAYER_STATE_READY:
+ new_status = ECORDOVA_MEDIA_STATUS_MEDIA_STOPPED;
+ break;
+ case PLAYER_STATE_PLAYING:
+ new_status = ECORDOVA_MEDIA_STATUS_MEDIA_RUNNING;
+ break;
+ case PLAYER_STATE_PAUSED:
+ new_status = ECORDOVA_MEDIA_STATUS_MEDIA_PAUSED;
+ break;
+ }
+
+ if (new_status == pd->status)
+ return;
+
+ pd->status = new_status;
+ eo_do(pd->obj, eo_event_callback_call(ECORDOVA_MEDIA_EVENT_MEDIA_STATUS, &pd->status));
+}
+
+static void
+_release(Ecordova_Media_Data *pd)
+{
+ if (pd->player)
+ {
+ player_unset_error_cb(pd->player);
+ player_unset_completed_cb(pd->player);
+ if (ECORDOVA_MEDIA_STATUS_MEDIA_NONE != pd->status)
+ player_unprepare(pd->player);
+ player_destroy(pd->player);
+ pd->player = NULL;
+ }
+
+ if (pd->recorder)
+ {
+ recorder_unset_state_changed_cb(pd->recorder);
+ recorder_state_e state = RECORDER_STATE_NONE;
+ if (RECORDER_ERROR_NONE == recorder_get_state(pd->recorder, &state) &&
+ RECORDER_STATE_NONE != state && RECORDER_STATE_CREATED != state)
+ recorder_unprepare(pd->recorder);
+ recorder_destroy(pd->recorder);
+ pd->recorder = NULL;
+ }
+
+ Action *action;
+ EINA_LIST_FREE(pd->pending, action)
+ {
+ free(action->data);
+ free(action);
+ }
+}
+
+static void
+_state_changed_cb(recorder_state_e previous,
+ recorder_state_e current,
+ bool by_policy EINA_UNUSED,
+ void *data)
+{
+ Ecordova_Media_Data *pd = data;
+ if (RECORDER_STATE_READY == current && pd->record_pending)
+ {
+ _start_record(pd);
+ return;
+ }
+
+ if (RECORDER_STATE_RECORDING == current)
+ pd->record_pending = false;
+
+ // TODO: Check what thread this callback is running to make sure it's on the main thread
+ if (RECORDER_STATE_RECORDING == previous && RECORDER_STATE_READY == current)
+ eo_do(pd->obj, eo_event_callback_call(ECORDOVA_MEDIA_EVENT_MEDIA_SUCCESS, NULL));
+}
+
+static void
+_start_record(Ecordova_Media_Data *pd)
+{
+ int ret = recorder_start(pd->recorder);
+ EINA_SAFETY_ON_FALSE_RETURN(RECORDER_ERROR_NONE == ret);
+}
+
+#include "ecordova_media.eo.c"
diff --git a/src/lib/ecordova/ecordova_media.eo b/src/lib/ecordova/ecordova_media.eo
new file mode 100644
index 0000000000..e64b2b3d8a
--- /dev/null
+++ b/src/lib/ecordova/ecordova_media.eo
@@ -0,0 +1,108 @@
+enum Ecordova_Media_Status {
+ MEDIA_NONE = 0,
+ MEDIA_STARTING = 1,
+ MEDIA_RUNNING = 2,
+ MEDIA_PAUSED = 3,
+ MEDIA_STOPPED = 4
+}
+
+enum Ecordova_Media_ErrorCode {
+ MEDIA_ERR_ABORTED = 1,
+ MEDIA_ERR_NETWORK = 2,
+ MEDIA_ERR_DECODE = 3,
+ MEDIA_ERR_NONE_SUPPORTED = 4
+}
+
+struct Ecordova_Media_Error {
+ [[A MediaError object is returned to the mediaError callback function when an error occurs.]]
+ code: int; [[One of the predefined error codes]]
+ message: const(char)*; [[An error message describing the details of the error.]]
+}
+
+class Ecordova.Media (Eo.Base) {
+ [[Ecordova Media Plugin
+ Plugin ID: org.apache.cordova.media
+ http://plugins.cordova.io/#/package/org.apache.cordova.media
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_Media constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ params {
+ src: const(char)*; [[A URI containing the audio content.]]
+ }
+ }
+ current_position_get {
+ [[Returns the current position within an audio file. Also updates
+ the Media object's position parameter.]]
+ }
+ duration_get {
+ [[Returns the duration of an audio file in seconds. If the
+ duration is unknown, it returns a value of -1.]]
+ return: int;
+ }
+ pause {
+ [[Pauses playing an audio file.]]
+ }
+ play {
+ [[Starts or resumes playing an audio file.]]
+ }
+ release {
+ [[Releases the underlying operating system's audio resources. This
+ is particularly important for Android, since there are a finite
+ amount of OpenCore instances for media playback. Applications
+ should call the release function for any Media resource that is
+ no longer needed.]]
+ }
+ seek {
+ [[Sets the current position within an audio file.]]
+ params {
+ milliseconds: int;
+ [[The position to set the playback position within the audio,
+ in milliseconds.]]
+ }
+ }
+ volume_set {
+ [[Set the volume for an audio file.]]
+ params {
+ volume: double;
+ [[The volume to set for playback. The value must be within the
+ range of 0.0 to 1.0.]]
+ }
+ }
+ record_start {
+ [[Starts recording an audio file.]]
+ }
+ stop {
+ [[Stops playing an audio file.]]
+ }
+ record_stop {
+ [[Stops recording an audio file.]]
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ media,position: int;
+ [[The callback that is passed the current position in seconds.]]
+
+ media,success;
+ [[The callback that executes after a Media object has completed the
+ current play, record, or stop action.]]
+
+ media,error;
+ [[The callback that executes if an error occurs.]]
+
+ media,status: Ecordova_Media_Status;
+ [[The callback that executes to indicate status changes.]]
+ }
+}
diff --git a/src/lib/ecordova/ecordova_media_private.h b/src/lib/ecordova/ecordova_media_private.h
new file mode 100644
index 0000000000..84d7dbe9ec
--- /dev/null
+++ b/src/lib/ecordova/ecordova_media_private.h
@@ -0,0 +1,26 @@
+#ifndef _ECORDOVA_MEDIA_PRIVATE_H
+#define _ECORDOVA_MEDIA_PRIVATE_H
+
+#include "ecordova_private.h"
+
+#include <player.h>
+#include <recorder.h>
+
+#include <stdbool.h>
+
+typedef struct _Ecordova_Media_Data Ecordova_Media_Data;
+
+/**
+ * Ecordova.Media private data
+ */
+struct _Ecordova_Media_Data
+{
+ Eo *obj;
+ player_h player;
+ recorder_h recorder;
+ Ecordova_Media_Status status;
+ Eina_List *pending;
+ bool record_pending;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_mediafile.c b/src/lib/ecordova/ecordova_mediafile.c
new file mode 100644
index 0000000000..b227835cde
--- /dev/null
+++ b/src/lib/ecordova/ecordova_mediafile.c
@@ -0,0 +1,187 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_mediafile_private.h"
+#include <stdbool.h>
+#include <limits.h>
+
+#define MY_CLASS ECORDOVA_MEDIAFILE_CLASS
+#define MY_CLASS_NAME "Ecordova_MediaFile"
+
+static void _extract_cb(void *, Ecore_Thread *);
+static void _extract_end_cb(void *, Ecore_Thread *);
+static void _extract_cancel_cb(void *, Ecore_Thread *);
+static void _internal_error_notify(Ecordova_MediaFile_Data *pd);
+static bool _bool_metadata_get(metadata_extractor_h, metadata_extractor_attr_e);
+static int _int_metadata_get(metadata_extractor_h, metadata_extractor_attr_e);
+
+#define NO_ERROR (INT_MAX)
+
+static Eo_Base *
+_ecordova_mediafile_eo_base_constructor(Eo *obj, Ecordova_MediaFile_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->extractor = NULL;
+ pd->error = NO_ERROR;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_mediafile_constructor(Eo *obj,
+ Ecordova_MediaFile_Data *pd EINA_UNUSED,
+ const char *name,
+ const char *url,
+ const char *type,
+ time_t last_modified_date,
+ long size)
+{
+ DBG("(%p)", obj);
+ eo_do_super(obj, MY_CLASS, ecordova_file_constructor(name,
+ url,
+ type,
+ last_modified_date,
+ size));
+}
+
+static void
+_ecordova_mediafile_eo_base_destructor(Eo *obj, Ecordova_MediaFile_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ if (pd->extractor)
+ metadata_extractor_destroy(pd->extractor);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_mediafile_format_data_get(Eo *obj EINA_UNUSED,
+ Ecordova_MediaFile_Data *pd)
+{
+ Ecore_Thread *thread = ecore_thread_run(_extract_cb,
+ _extract_end_cb,
+ _extract_cancel_cb,
+ pd);
+ if (!thread)
+ _internal_error_notify(pd);
+}
+
+static void
+_extract_cb(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+ Ecordova_MediaFile_Data *pd = data;
+ int ret;
+
+ if (!pd->extractor)
+ {
+ ret = metadata_extractor_create(&pd->extractor);
+ if (METADATA_EXTRACTOR_ERROR_NONE != ret)
+ goto on_error;
+
+ const char *url = eo_do_super_ret(pd->obj,
+ MY_CLASS,
+ url,
+ ecordova_file_url_get());
+ ret = metadata_extractor_set_path(pd->extractor, url);
+ if (METADATA_EXTRACTOR_ERROR_NONE != ret)
+ goto on_error;
+ }
+
+ pd->metadata.codecs = NULL; // TODO: what is it?
+ pd->metadata.duration = _int_metadata_get(pd->extractor, METADATA_DURATION) / 1000;
+
+ bool has_video = _bool_metadata_get(pd->extractor, METADATA_HAS_VIDEO);
+ bool has_audio = _bool_metadata_get(pd->extractor, METADATA_HAS_AUDIO);
+
+ DBG("has_video=%d, has_audio=%d", has_video, has_audio);
+ if (has_video)
+ {
+ pd->metadata.width = _int_metadata_get(pd->extractor, METADATA_VIDEO_WIDTH);
+ pd->metadata.height = _int_metadata_get(pd->extractor, METADATA_VIDEO_HEIGHT);
+ pd->metadata.bitrate = _int_metadata_get(pd->extractor, METADATA_VIDEO_BITRATE);
+ }
+ else
+ {
+ pd->metadata.bitrate = _int_metadata_get(pd->extractor, METADATA_AUDIO_BITRATE);
+ }
+
+ pd->error = NO_ERROR;
+ return;
+
+on_error:
+ pd->error = ECORDOVA_CAPTURE_ERRORCODE_CAPTURE_INTERNAL_ERR;
+}
+
+static void
+_extract_end_cb(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+ Ecordova_MediaFile_Data *pd = data;
+ if (NO_ERROR != pd->error)
+ {
+ Ecordova_Capture_Error error = {.code = pd->error};
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_MEDIAFILE_EVENT_ERROR,
+ &error));
+ return;
+ }
+
+ eo_do(pd->obj,
+ eo_event_callback_call(ECORDOVA_MEDIAFILE_EVENT_SUCCESS,
+ &pd->metadata));
+}
+
+static void
+_extract_cancel_cb(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+ Ecordova_MediaFile_Data *pd = data;
+ _internal_error_notify(pd);
+}
+
+static void
+_internal_error_notify(Ecordova_MediaFile_Data *pd)
+{
+ Ecordova_Capture_Error error = {
+ .code = ECORDOVA_CAPTURE_ERRORCODE_CAPTURE_INTERNAL_ERR
+ };
+ eo_do(pd->obj, eo_event_callback_call(ECORDOVA_MEDIAFILE_EVENT_ERROR, &error));
+}
+
+static bool
+_bool_metadata_get(metadata_extractor_h extractor,
+ metadata_extractor_attr_e attr)
+{
+ bool result = false;
+ char *value = NULL;
+ int ret = metadata_extractor_get_metadata(extractor, attr, &value);
+ if (value)
+ {
+ result = strcmp(value, "TRUE") == 0;
+ free(value);
+ }
+
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(METADATA_EXTRACTOR_ERROR_NONE == ret, false);
+ return result;
+}
+
+static int
+_int_metadata_get(metadata_extractor_h extractor,
+ metadata_extractor_attr_e attr)
+{
+ int result = 0;
+ char *value = NULL;
+ int ret = metadata_extractor_get_metadata(extractor, attr, &value);
+ if (value)
+ {
+ result = atoi(value);
+ free(value);
+ }
+
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(METADATA_EXTRACTOR_ERROR_NONE == ret, 0);
+ return result;
+}
+
+#include "ecordova_mediafile.eo.c"
diff --git a/src/lib/ecordova/ecordova_mediafile.eo b/src/lib/ecordova/ecordova_mediafile.eo
new file mode 100644
index 0000000000..b1ebd52eb5
--- /dev/null
+++ b/src/lib/ecordova/ecordova_mediafile.eo
@@ -0,0 +1,62 @@
+struct Ecordova_MediaFileData {
+ [[Encapsulates format information about a media file.]]
+
+ codecs: const(char)*;
+ [[The actual format of the audio and video content.]]
+
+ bitrate: int;
+ [[The average bitrate of the content. The value is zero for images.]]
+
+ height: int;
+ [[The height of the image or video in pixels. The value is zero for audio
+ clips.]]
+
+ width: int;
+ [[The width of the image or video in pixels. The value is zero for audio
+ clips.]]
+
+ duration: int;
+ [[The length of the video or sound clip in seconds. The value is zero for
+ images.]]
+}
+
+class Ecordova.MediaFile (Ecordova.File) {
+ [[Represents a single media file.]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_MediaFile constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ params {
+ name: const(char)*; [[name of the file, without path information]]
+ url: const(char)*; [[the full path of the file, including the name]]
+ type: const(char)*; [[mime type]]
+ last_modified_date: time; [[last modified date]]
+ size: long; [[size of the file in bytes]]
+ }
+ }
+ format_data_get {
+ [[Retrieves format information about the media capture file.
+
+ This function asynchronously attempts to retrieve the format
+ information for the media file. If successful, it invokes the
+ MediaFileDataSuccessCB callback with a MediaFileData object. If
+ the attempt fails, this function invokes the
+ MediaFileDataErrorCB callback.]]
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ success: const(Ecordova_MediaFileData)*;
+ error: const(Ecordova.Capture.Error)*;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_mediafile_private.h b/src/lib/ecordova/ecordova_mediafile_private.h
new file mode 100644
index 0000000000..1e7e8621d2
--- /dev/null
+++ b/src/lib/ecordova/ecordova_mediafile_private.h
@@ -0,0 +1,21 @@
+#ifndef _ECORDOVA_MEDIAFILE_PRIVATE_H
+#define _ECORDOVA_MEDIAFILE_PRIVATE_H
+
+#include "ecordova_private.h"
+
+#include <metadata_extractor.h>
+
+typedef struct _Ecordova_MediaFile_Data Ecordova_MediaFile_Data;
+
+/**
+ * Ecordova.MediaFile private data
+ */
+struct _Ecordova_MediaFile_Data
+{
+ Eo *obj;
+ metadata_extractor_h extractor;
+ Ecordova_Capture_ErrorCode error;
+ Ecordova_MediaFileData metadata;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_networkinformation.c b/src/lib/ecordova/ecordova_networkinformation.c
new file mode 100644
index 0000000000..e89dc7018a
--- /dev/null
+++ b/src/lib/ecordova/ecordova_networkinformation.c
@@ -0,0 +1,98 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_networkinformation_private.h"
+
+#define MY_CLASS ECORDOVA_NETWORKINFORMATION_CLASS
+#define MY_CLASS_NAME "Ecordova_NetworkInformation"
+
+static void _type_changed_cb(connection_type_e, void *);
+static Ecordova_NetworkInformation_ConnectionType _to_connection_type(connection_type_e);
+
+static Eo_Base *
+_ecordova_networkinformation_eo_base_constructor(Eo *obj,
+ Ecordova_NetworkInformation_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->connection = NULL;
+ int ret = connection_create(&pd->connection);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONNECTION_ERROR_NONE == ret, NULL);
+
+ ret = connection_set_type_changed_cb(pd->connection, _type_changed_cb, obj);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONNECTION_ERROR_NONE == ret, NULL);
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_networkinformation_constructor(Eo *obj EINA_UNUSED,
+ Ecordova_NetworkInformation_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+}
+
+static void
+_ecordova_networkinformation_eo_base_destructor(Eo *obj,
+ Ecordova_NetworkInformation_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ int ret = connection_unset_type_changed_cb(pd->connection);
+ EINA_SAFETY_ON_FALSE_RETURN(CONNECTION_ERROR_NONE == ret);
+
+ ret = connection_destroy(pd->connection);
+ EINA_SAFETY_ON_FALSE_RETURN(CONNECTION_ERROR_NONE == ret);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static Ecordova_NetworkInformation_ConnectionType
+_ecordova_networkinformation_type_get(Eo *obj,
+ Ecordova_NetworkInformation_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ connection_type_e type;
+
+ int ret = connection_get_type(pd->connection, &type);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(CONNECTION_ERROR_NONE == ret,
+ ECORDOVA_NETWORKINFORMATION_CONNECTIONTYPE_UNKNOWN);
+
+ return _to_connection_type(type);
+}
+
+static Ecordova_NetworkInformation_ConnectionType
+_to_connection_type(connection_type_e type)
+{
+ switch (type)
+ {
+ case CONNECTION_TYPE_DISCONNECTED:
+ return ECORDOVA_NETWORKINFORMATION_CONNECTIONTYPE_NONE;
+ case CONNECTION_TYPE_WIFI:
+ return ECORDOVA_NETWORKINFORMATION_CONNECTIONTYPE_WIFI;
+ case CONNECTION_TYPE_CELLULAR:
+ return ECORDOVA_NETWORKINFORMATION_CONNECTIONTYPE_CELL;
+ case CONNECTION_TYPE_ETHERNET:
+ return ECORDOVA_NETWORKINFORMATION_CONNECTIONTYPE_ETHERNET;
+ case CONNECTION_TYPE_BT:
+ return ECORDOVA_NETWORKINFORMATION_CONNECTIONTYPE_UNKNOWN;
+ }
+
+ return ECORDOVA_NETWORKINFORMATION_CONNECTIONTYPE_UNKNOWN;
+}
+
+static void
+_type_changed_cb(connection_type_e type, void *user_data)
+{
+ Eo *obj = user_data;
+
+ const Eo_Event_Description *event =
+ CONNECTION_TYPE_DISCONNECTED == type ? ECORDOVA_NETWORKINFORMATION_EVENT_OFFLINE
+ : ECORDOVA_NETWORKINFORMATION_EVENT_ONLINE;
+ eo_do(obj, eo_event_callback_call(event, NULL));
+}
+
+#include "ecordova_networkinformation.eo.c"
diff --git a/src/lib/ecordova/ecordova_networkinformation.eo b/src/lib/ecordova/ecordova_networkinformation.eo
new file mode 100644
index 0000000000..bff5810354
--- /dev/null
+++ b/src/lib/ecordova/ecordova_networkinformation.eo
@@ -0,0 +1,61 @@
+enum Ecordova_NetworkInformation_ConnectionType {
+ UNKNOWN,
+ ETHERNET,
+ WIFI,
+ CELL_2G,
+ CELL_3G,
+ CELL_4G,
+ CELL,
+ NONE
+}
+
+class Ecordova.NetworkInformation (Eo.Base) {
+ [[Ecordova Network-Information Plugin
+ Plugin ID: org.apache.cordova.network-information
+ http://plugins.cordova.io/#/package/org.apache.cordova.network-information
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_NetworkInformation constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ }
+ @property type {
+ [[This property offers a fast way to determine the device's
+ network connection state, and type of connection.]]
+ get{}
+ values {
+ value: Ecordova_NetworkInformation_ConnectionType;
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ offline;
+ [[The event fires when an application goes offline, and the device is
+ not connected to the Internet.
+
+ The offline event fires when a previously connected device loses a
+ network connection so that an application can no longer access the
+ Internet. It relies on the same information as the Connection API,
+ and fires when the value of connection.type becomes NONE.]]
+
+ online;
+ [[This event fires when an application goes online, and the device
+ becomes connected to the Internet.
+
+ The online event fires when a previously unconnected device receives
+ a network connection to allow an application access to the Internet.
+ It relies on the same information as the Connection API, and fires
+ when the connection.type changes from NONE to any other value.]]
+ }
+}
diff --git a/src/lib/ecordova/ecordova_networkinformation_private.h b/src/lib/ecordova/ecordova_networkinformation_private.h
new file mode 100644
index 0000000000..1af4d1e22e
--- /dev/null
+++ b/src/lib/ecordova/ecordova_networkinformation_private.h
@@ -0,0 +1,19 @@
+#ifndef _ECORDOVA_NETWORKINFORMATION_PRIVATE_H
+#define _ECORDOVA_NETWORKINFORMATION_PRIVATE_H
+
+#include "ecordova_private.h"
+
+#include <net_connection.h>
+
+typedef struct _Ecordova_NetworkInformation_Data Ecordova_NetworkInformation_Data;
+
+/**
+ * Ecordova.NetworkInformation private data
+ */
+struct _Ecordova_NetworkInformation_Data
+{
+ Eo *obj;
+ connection_h connection;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_private.h b/src/lib/ecordova/ecordova_private.h
new file mode 100644
index 0000000000..231e2d93d7
--- /dev/null
+++ b/src/lib/ecordova/ecordova_private.h
@@ -0,0 +1,54 @@
+#ifndef _ECORDOVA_PRIVATE_H
+#define _ECORDOVA_PRIVATE_H
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "Ecordova.h"
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORDOVA_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_ECORDOVA_BUILD */
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif
+
+#include <stdbool.h>
+
+/* logging support */
+extern int _ecordova_log_dom;
+
+#define CRI(...) EINA_LOG_DOM_CRIT(_ecordova_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_ecordova_log_dom, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(_ecordova_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_ecordova_log_dom, __VA_ARGS__)
+#define DBG(...) EINA_LOG_DOM_DBG(_ecordova_log_dom, __VA_ARGS__)
+
+#define MIN(x, y) (((x) > (y)) ? (y) : (x))
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+
+extern Eo* _ecordova_systeminfo;
+
+#undef EAPI
+#define EAPI
+
+#endif
diff --git a/src/lib/ecordova/ecordova_splashscreen.c b/src/lib/ecordova/ecordova_splashscreen.c
new file mode 100644
index 0000000000..6b3498d454
--- /dev/null
+++ b/src/lib/ecordova/ecordova_splashscreen.c
@@ -0,0 +1,51 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_splashscreen_private.h"
+
+#define MY_CLASS ECORDOVA_SPLASHSCREEN_CLASS
+#define MY_CLASS_NAME "Ecordova_Splashscreen"
+
+static Eo_Base *
+_ecordova_splashscreen_eo_base_constructor(Eo *obj,
+ Ecordova_Splashscreen_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_splashscreen_constructor(Eo *obj EINA_UNUSED,
+ Ecordova_Splashscreen_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+}
+
+static void
+_ecordova_splashscreen_eo_base_destructor(Eo *obj,
+ Ecordova_Splashscreen_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_splashscreen_show(Eo *obj EINA_UNUSED,
+ Ecordova_Splashscreen_Data *pd EINA_UNUSED)
+{
+ ERR("Not implemented.");
+}
+
+static void
+_ecordova_splashscreen_hide(Eo *obj EINA_UNUSED,
+ Ecordova_Splashscreen_Data *pd EINA_UNUSED)
+{
+ ERR("Not implemented.");
+}
+
+#include "ecordova_splashscreen.eo.c"
diff --git a/src/lib/ecordova/ecordova_splashscreen.eo b/src/lib/ecordova/ecordova_splashscreen.eo
new file mode 100644
index 0000000000..88346ad04c
--- /dev/null
+++ b/src/lib/ecordova/ecordova_splashscreen.eo
@@ -0,0 +1,29 @@
+class Ecordova.Splashscreen (Eo.Base) {
+ [[Ecordova Splashscreen Plugin
+ Plugin ID: org.apache.cordova.splashscreen
+ http://plugins.cordova.io/#/package/org.apache.cordova.splashscreen
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_Splashscreen constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ }
+ show {
+ [[Displays the splash screen.]]
+ }
+ hide {
+ [[Dismiss the splash screen.]]
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_splashscreen_private.h b/src/lib/ecordova/ecordova_splashscreen_private.h
new file mode 100644
index 0000000000..5f1fc311c7
--- /dev/null
+++ b/src/lib/ecordova/ecordova_splashscreen_private.h
@@ -0,0 +1,16 @@
+#ifndef _ECORDOVA_SPLASHSCREEN_PRIVATE_H
+#define _ECORDOVA_SPLASHSCREEN_PRIVATE_H
+
+#include "ecordova_private.h"
+
+typedef struct _Ecordova_Splashscreen_Data Ecordova_Splashscreen_Data;
+
+/**
+ * Ecordova.Splashscreen private data
+ */
+struct _Ecordova_Splashscreen_Data
+{
+ Eo *obj;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_systeminfo.c b/src/lib/ecordova/ecordova_systeminfo.c
new file mode 100644
index 0000000000..0dc4f7f971
--- /dev/null
+++ b/src/lib/ecordova/ecordova_systeminfo.c
@@ -0,0 +1,139 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_systeminfo_private.h"
+
+#include <vconf.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define MY_CLASS ECORDOVA_SYSTEMINFO_CLASS
+#define MY_CLASS_NAME "Ecordova_SystemInfo"
+
+static Eina_Bool _add_cb(void *, Eo *, const Eo_Event_Description *, void *);
+static Eina_Bool _del_cb(void *, Eo *, const Eo_Event_Description *, void *);
+static void _battery_callback_add(Ecordova_SystemInfo_Data *);
+static void _battery_callback_del(Ecordova_SystemInfo_Data *);
+static void _on_battery_changed(keynode_t *, void *);
+
+static Eo *
+_ecordova_systeminfo_eo_base_constructor(Eo *obj,
+ Ecordova_SystemInfo_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_systeminfo_constructor(Eo *obj,
+ Ecordova_SystemInfo_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ eo_do(obj, eo_event_callback_add(EO_EV_CALLBACK_ADD, _add_cb, pd));
+ eo_do(obj, eo_event_callback_add(EO_EV_CALLBACK_DEL, _del_cb, pd));
+}
+
+static void
+_ecordova_systeminfo_eo_base_destructor(Eo *obj,
+ Ecordova_SystemInfo_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ if (pd->ref_count > 0)
+ _battery_callback_del(pd);
+
+ eo_do(obj, eo_event_callback_del(EO_EV_CALLBACK_ADD, _add_cb, pd));
+ eo_do(obj, eo_event_callback_del(EO_EV_CALLBACK_DEL, _del_cb, pd));
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static Eina_Bool
+_add_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc,
+ void *event_info)
+{
+ Ecordova_SystemInfo_Data *pd = (Ecordova_SystemInfo_Data*)data;
+ const Eo_Callback_Array_Item *array = (const Eo_Callback_Array_Item*)event_info;
+
+ for (size_t i = 0; (desc = array[i].desc); ++i)
+ {
+ if (ECORDOVA_SYSTEMINFO_EVENT_BATTERY_CHANGED != desc) continue;
+
+ ++pd->ref_count;
+ if (1 == pd->ref_count)
+ _battery_callback_add(pd);
+ }
+
+ return EO_CALLBACK_CONTINUE;
+}
+
+static Eina_Bool
+_del_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc,
+ void *event_info)
+{
+ Ecordova_SystemInfo_Data *pd = (Ecordova_SystemInfo_Data*)data;
+ const Eo_Callback_Array_Item *array = (const Eo_Callback_Array_Item*)event_info;
+
+ for (size_t i = 0; (desc = array[i].desc); ++i)
+ {
+ if (ECORDOVA_SYSTEMINFO_EVENT_BATTERY_CHANGED != desc) continue;
+
+ --pd->ref_count;
+ if (0 == pd->ref_count)
+ _battery_callback_del(pd);
+ }
+
+ return EO_CALLBACK_CONTINUE;
+}
+
+static void
+_register_vconf_callback(Ecordova_SystemInfo_Data *pd,
+ const char *in_key,
+ vconf_callback_fn cb)
+{
+ if (0 != vconf_notify_key_changed(in_key, cb, pd))
+ ERR("%s, %s", "Failed to register vconf callback", in_key);
+}
+
+static void
+_unregister_vconf_callback(const char *in_key,
+ vconf_callback_fn cb)
+{
+ if (0 != vconf_ignore_key_changed(in_key, cb))
+ ERR("%s, %s", "Failed to unregister vconf callback", in_key);
+}
+
+static void
+_battery_callback_add(Ecordova_SystemInfo_Data *pd)
+{
+ _register_vconf_callback(pd, VCONFKEY_SYSMAN_BATTERY_CAPACITY, _on_battery_changed);
+ _register_vconf_callback(pd, VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, _on_battery_changed);
+}
+
+static void
+_battery_callback_del(Ecordova_SystemInfo_Data *pd EINA_UNUSED)
+{
+ _unregister_vconf_callback(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, _on_battery_changed);
+ _unregister_vconf_callback(VCONFKEY_SYSMAN_BATTERY_CAPACITY, _on_battery_changed);
+}
+
+static void
+_on_battery_changed(keynode_t *node EINA_UNUSED, void *data)
+{
+ Ecordova_SystemInfo_Data *pd = (Ecordova_SystemInfo_Data*)data;
+ eo_do(pd->obj, eo_event_callback_call
+ (ECORDOVA_SYSTEMINFO_EVENT_BATTERY_CHANGED, NULL));
+}
+
+#include "ecordova_systeminfo.eo.c"
diff --git a/src/lib/ecordova/ecordova_systeminfo.eo b/src/lib/ecordova/ecordova_systeminfo.eo
new file mode 100644
index 0000000000..2405400396
--- /dev/null
+++ b/src/lib/ecordova/ecordova_systeminfo.eo
@@ -0,0 +1,27 @@
+class Ecordova.SystemInfo (Eo.Base) {
+ [[Ecordova System Information Service
+ wrt-plugins-tizen SystemInfo.h
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_SystemInfo constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+ events {
+ battery,changed;
+ [[This event fires when the percentage of battery charge changes by at
+ least 1 percent, or if the device is plugged in or unplugged.]]
+ }
+}
diff --git a/src/lib/ecordova/ecordova_systeminfo_private.h b/src/lib/ecordova/ecordova_systeminfo_private.h
new file mode 100644
index 0000000000..fceab8c631
--- /dev/null
+++ b/src/lib/ecordova/ecordova_systeminfo_private.h
@@ -0,0 +1,19 @@
+#ifndef _ECORDOVA_SYSTEMINFO_PRIVATE_H
+#define _ECORDOVA_SYSTEMINFO_PRIVATE_H
+
+#include "ecordova_private.h"
+#include "ecordova_systeminfo.eo.h"
+
+typedef struct _Ecordova_SystemInfo_Data Ecordova_SystemInfo_Data;
+
+/**
+ * Ecordova.SystemInfo private data
+ */
+struct _Ecordova_SystemInfo_Data
+{
+ Eo *obj;
+ int ref_count;
+ bool info_initialized;
+};
+
+#endif
diff --git a/src/lib/ecordova/ecordova_vibration.c b/src/lib/ecordova/ecordova_vibration.c
new file mode 100644
index 0000000000..6d2427e1d5
--- /dev/null
+++ b/src/lib/ecordova/ecordova_vibration.c
@@ -0,0 +1,66 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_vibration_private.h"
+
+#include <haptic.h>
+
+#define MY_CLASS ECORDOVA_VIBRATION_CLASS
+#define MY_CLASS_NAME "Ecordova_Vibration"
+
+static size_t _ref_count = 0;
+
+static Eo_Base *
+_ecordova_vibration_eo_base_constructor(Eo *obj, Ecordova_Vibration_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+
+ ++_ref_count;
+ if (1 == _ref_count)
+ {
+ int ret = haptic_initialize();
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(HAPTIC_ERROR_NONE == ret, NULL);
+ }
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_ecordova_vibration_constructor(Eo *obj EINA_UNUSED,
+ Ecordova_Vibration_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+}
+
+static void
+_ecordova_vibration_eo_base_destructor(Eo *obj,
+ Ecordova_Vibration_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+
+ EINA_SAFETY_ON_FALSE_RETURN(_ref_count >= 1);
+
+ --_ref_count;
+ if (0 == _ref_count)
+ {
+ int ret = haptic_deinitialize();
+ EINA_SAFETY_ON_FALSE_RETURN(HAPTIC_ERROR_NONE == ret);
+ }
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static void
+_ecordova_vibration_vibrate(Eo *obj,
+ Ecordova_Vibration_Data *pd EINA_UNUSED,
+ int time)
+{
+ DBG("(%p)", obj);
+ int ret = haptic_vibrate_monotone(0, time, 100);
+ EINA_SAFETY_ON_FALSE_RETURN(HAPTIC_ERROR_NONE == ret);
+}
+
+#include "ecordova_vibration.eo.c"
diff --git a/src/lib/ecordova/ecordova_vibration.eo b/src/lib/ecordova/ecordova_vibration.eo
new file mode 100644
index 0000000000..498791024f
--- /dev/null
+++ b/src/lib/ecordova/ecordova_vibration.eo
@@ -0,0 +1,30 @@
+class Ecordova.Vibration (Eo.Base) {
+ [[Ecordova Vibration Plugin
+ Plugin ID: org.apache.cordova.vibration
+ http://plugins.cordova.io/#/package/org.apache.cordova.vibration
+ ]]
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Ecordova_Vibration constructor.
+ @.constructor
+
+ @since 2.3
+ ]]
+ }
+ vibrate {
+ [[This function has three different functionalities based on
+ parameters passed to it.]]
+ params {
+ time: int; [[Milliseconds to vibrate the device.]]
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ }
+ constructors {
+ .constructor;
+ }
+}
diff --git a/src/lib/ecordova/ecordova_vibration_private.h b/src/lib/ecordova/ecordova_vibration_private.h
new file mode 100644
index 0000000000..f2921bfa47
--- /dev/null
+++ b/src/lib/ecordova/ecordova_vibration_private.h
@@ -0,0 +1,16 @@
+#ifndef _ECORDOVA_VIBRATION_PRIVATE_H
+#define _ECORDOVA_VIBRATION_PRIVATE_H
+
+#include "ecordova_private.h"
+
+typedef struct _Ecordova_Vibration_Data Ecordova_Vibration_Data;
+
+/**
+ * Ecordova.Vibration private data
+ */
+struct _Ecordova_Vibration_Data
+{
+ Eo *obj;
+};
+
+#endif
diff --git a/src/tests/ecordova/44khz32kbps.mp3 b/src/tests/ecordova/44khz32kbps.mp3
new file mode 100644
index 0000000000..df1594f2b7
--- /dev/null
+++ b/src/tests/ecordova/44khz32kbps.mp3
Binary files differ
diff --git a/src/tests/ecordova/ecordova_batterystatus_test.c b/src/tests/ecordova/ecordova_batterystatus_test.c
new file mode 100644
index 0000000000..140723402d
--- /dev/null
+++ b/src/tests/ecordova/ecordova_batterystatus_test.c
@@ -0,0 +1,44 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_batterystatus_test.h"
+#include "ecordova_suite.h"
+
+#include <stdbool.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Ecordova_Device *
+_batterystatus_new(void)
+{
+ return eo_add(ECORDOVA_BATTERYSTATUS_CLASS,
+ NULL,
+ ecordova_batterystatus_constructor());
+}
+
+START_TEST(smoke)
+{
+ Ecordova_Device *batterystatus = _batterystatus_new();
+ eo_unref(batterystatus);
+}
+END_TEST
+
+void
+ecordova_batterystatus_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, smoke);
+}
diff --git a/src/tests/ecordova/ecordova_batterystatus_test.h b/src/tests/ecordova/ecordova_batterystatus_test.h
new file mode 100644
index 0000000000..55f29347e8
--- /dev/null
+++ b/src/tests/ecordova/ecordova_batterystatus_test.h
@@ -0,0 +1,9 @@
+#ifndef _ECORDOVA_BATTERYSTATUS_TEST_H
+#define _ECORDOVA_BATTERYSTATUS_TEST_H
+
+#include <Ecordova.h>
+#include <check.h>
+
+void ecordova_batterystatus_test(TCase *);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_console_test.c b/src/tests/ecordova/ecordova_console_test.c
new file mode 100644
index 0000000000..35e916b81e
--- /dev/null
+++ b/src/tests/ecordova/ecordova_console_test.c
@@ -0,0 +1,140 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_console_test.h"
+#include "ecordova_suite.h"
+
+#include <stdbool.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Ecordova_Device *
+_console_new(void)
+{
+ return eo_add(ECORDOVA_CONSOLE_CLASS,
+ NULL,
+ ecordova_console_constructor());
+}
+
+START_TEST(smoke)
+{
+ Ecordova_Device *console = _console_new();
+ eo_unref(console);
+}
+END_TEST
+
+START_TEST(level)
+{
+ Ecordova_Device *console = _console_new();
+
+ Ecordova_Console_LoggerLevel level = eo_do_ret(console,
+ level,
+ ecordova_console_level_get());
+ ck_assert_int_eq(level, ECORDOVA_CONSOLE_LOGGERLEVEL_LOG); // default value
+
+ for (Ecordova_Console_LoggerLevel new_level = ECORDOVA_CONSOLE_LOGGERLEVEL_LOG;
+ new_level < ECORDOVA_CONSOLE_LOGGERLEVEL_LAST;
+ ++new_level)
+ {
+ eo_do(console, ecordova_console_level_set(new_level));
+ level = eo_do_ret(console, level, ecordova_console_level_get());
+ ck_assert_int_eq(level, new_level);
+ }
+
+ eo_unref(console);
+}
+END_TEST
+
+START_TEST(console_use)
+{
+ Ecordova_Device *console = _console_new();
+
+ Eina_Bool actual_value = eo_do_ret(console,
+ actual_value,
+ ecordova_console_use_get());
+ ck_assert_int_eq(actual_value, EINA_FALSE); // default value
+
+ Eina_Bool expected_value = !actual_value;
+ eo_do(console, ecordova_console_use_set(expected_value));
+ actual_value = eo_do_ret(console, actual_value, ecordova_console_use_get());
+ ck_assert_int_eq(expected_value, actual_value);
+
+ expected_value = !actual_value;
+ eo_do(console, ecordova_console_use_set(expected_value));
+ actual_value = eo_do_ret(console, actual_value, ecordova_console_use_get());
+ ck_assert_int_eq(expected_value, actual_value);
+
+ eo_unref(console);
+}
+END_TEST
+
+START_TEST(logger_use)
+{
+ Ecordova_Device *console = _console_new();
+
+ Eina_Bool actual_value = eo_do_ret(console,
+ actual_value,
+ ecordova_console_logger_use_get());
+ ck_assert_int_eq(actual_value, EINA_TRUE); // default value
+
+ Eina_Bool expected_value = !actual_value;
+ eo_do(console, ecordova_console_logger_use_set(expected_value));
+ actual_value = eo_do_ret(console, actual_value, ecordova_console_logger_use_get());
+ ck_assert_int_eq(expected_value, actual_value);
+
+ expected_value = !actual_value;
+ eo_do(console, ecordova_console_logger_use_set(expected_value));
+ actual_value = eo_do_ret(console, actual_value, ecordova_console_logger_use_get());
+ ck_assert_int_eq(expected_value, actual_value);
+
+ eo_unref(console);
+}
+END_TEST
+
+START_TEST(logging)
+{
+ Ecordova_Device *console = _console_new();
+
+ eo_do(console, ecordova_console_logger_use_set(EINA_TRUE));
+ eo_do(console, ecordova_console_use_set(EINA_TRUE));
+
+ for (Ecordova_Console_LoggerLevel new_level = ECORDOVA_CONSOLE_LOGGERLEVEL_LOG;
+ new_level < ECORDOVA_CONSOLE_LOGGERLEVEL_LAST;
+ ++new_level)
+ {
+ eo_do(console, ecordova_console_level_set(new_level));
+
+ eo_do(console, ecordova_console_log("log"));
+ eo_do(console, ecordova_console_error("error"));
+ eo_do(console, ecordova_console_warn("warn"));
+ eo_do(console, ecordova_console_info("info"));
+ eo_do(console, ecordova_console_debug("debug"));
+ }
+
+ eo_unref(console);
+}
+END_TEST
+
+void
+ecordova_console_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, smoke);
+ tcase_add_test(tc, level);
+ tcase_add_test(tc, logger_use);
+ tcase_add_test(tc, console_use);
+ tcase_add_test(tc, logging);
+}
diff --git a/src/tests/ecordova/ecordova_console_test.h b/src/tests/ecordova/ecordova_console_test.h
new file mode 100644
index 0000000000..1d303fd499
--- /dev/null
+++ b/src/tests/ecordova/ecordova_console_test.h
@@ -0,0 +1,9 @@
+#ifndef _ECORDOVA_CONSOLE_TEST_H
+#define _ECORDOVA_CONSOLE_TEST_H
+
+#include <Ecordova.h>
+#include <check.h>
+
+void ecordova_console_test(TCase *);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_contacts_test.c b/src/tests/ecordova/ecordova_contacts_test.c
new file mode 100644
index 0000000000..29d40be36e
--- /dev/null
+++ b/src/tests/ecordova/ecordova_contacts_test.c
@@ -0,0 +1,255 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_contacts_test.h"
+#include "ecordova_suite.h"
+#include <Ecore.h>
+#include <ecore_timer.eo.h>
+#include <contacts.h>
+
+#define CHECK(x) {int ret = x; ck_assert_int_eq(CONTACTS_ERROR_NONE, ret);}
+
+static int _contact_id;
+static const char *_contact_name = "test";
+
+static void
+_setup(void)
+{
+ DBG("%s", "_setup");
+
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+
+ DBG("%s", "_setup");
+
+ CHECK(contacts_connect());
+
+ // TODO: delete all record in the database to be back to square 1 and make tests deterministic
+ DBG("%s", "_setup");
+
+ // create contact record
+ contacts_record_h contact = NULL;
+ CHECK(contacts_record_create(_contacts_contact._uri, &contact));
+
+ // add name
+ contacts_record_h name = NULL;
+ CHECK(contacts_record_create(_contacts_name._uri, &name));
+ CHECK(contacts_record_set_str(name, _contacts_name.first, _contact_name));
+ CHECK(contacts_record_add_child_record(contact, _contacts_contact.name, name));
+
+ CHECK(contacts_db_insert_record(contact, &_contact_id));
+
+ CHECK(contacts_record_destroy(contact, true));
+}
+
+static void
+_teardown(void)
+{
+ CHECK(contacts_db_delete_record(_contacts_contact._uri, _contact_id));
+
+ CHECK(contacts_disconnect());
+
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Eina_Bool
+_find_all_success_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ bool *success = data;
+ Eina_Array *contacts = event_info;
+ fail_if(NULL == contacts);
+
+ size_t count = eina_array_count(contacts);
+ DBG("# of contacts: %zu", count);
+
+ *success = true;
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+static Eina_Bool
+_find_one_contact_success_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ Ecordova_Contact **contact = data;
+ Eina_Array *contacts = event_info;
+ fail_if(NULL == contacts);
+
+ size_t count = eina_array_count(contacts);
+ DBG("# of contacts: %zu", count);
+
+ fail_if(1 != count);
+ *contact = eina_array_data_get(contacts, 0);
+ eo_ref(*contact);
+
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+static Eina_Bool
+_error_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ bool *error = data;
+ Ecordova_Contacts_Error *error_code = event_info;
+ fail_if(NULL == error_code);
+
+ *error = true;
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+static Eina_Bool
+_timeout_cb(void *data)
+{
+ bool *timeout = data;
+ *timeout = true;
+ ecore_main_loop_quit();
+ return ECORE_CALLBACK_CANCEL;
+}
+
+START_TEST(find_all)
+{
+ Ecordova_Contacts *contacts = eo_add(ECORDOVA_CONTACTS_CLASS, NULL);
+ fail_if(NULL == contacts);
+
+ bool success = false;
+ bool error = false;
+ bool timeout = false;
+
+ Ecore_Timer *timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+ eo_do(contacts, eo_event_callback_add(ECORDOVA_CONTACTS_EVENT_FIND_SUCCESS, _find_all_success_cb, &success));
+ eo_do(contacts, eo_event_callback_add(ECORDOVA_CONTACTS_EVENT_ERROR, _error_cb, &error));
+
+ Eina_List *fields = eina_list_append(NULL, "*");
+ Ecordova_Contacts_FindOptions *options = NULL;
+ eo_do(contacts, ecordova_contacts_find(fields, options));
+
+ ecore_main_loop_begin();
+
+ eina_list_free(fields);
+
+ eo_unref(timer);
+
+ fail_unless(success);
+ fail_if(error);
+ fail_if(timeout);
+
+ eo_unref(contacts);
+}
+END_TEST
+
+START_TEST(find_by_id)
+{
+ Ecordova_Contacts *contacts = eo_add(ECORDOVA_CONTACTS_CLASS, NULL);
+ fail_if(NULL == contacts);
+
+ Ecordova_Contact *contact = NULL;
+ bool error = false;
+ bool timeout = false;
+
+ Ecore_Timer *timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+ eo_do(contacts, eo_event_callback_add(ECORDOVA_CONTACTS_EVENT_FIND_SUCCESS, _find_one_contact_success_cb, &contact));
+ eo_do(contacts, eo_event_callback_add(ECORDOVA_CONTACTS_EVENT_ERROR, _error_cb, &error));
+
+
+ char buf[64];
+ snprintf(buf, sizeof(buf), "%d", _contact_id);
+
+ Eina_List *fields = eina_list_append(NULL, "id");
+ Ecordova_Contacts_FindOptions options = {
+ .filter = buf
+ };
+ eo_do(contacts, ecordova_contacts_find(fields, &options));
+
+ ecore_main_loop_begin();
+
+ eina_list_free(fields);
+
+ eo_unref(timer);
+
+ fail_unless(!!contact);
+ fail_if(error);
+ fail_if(timeout);
+
+ int actual_id, expected_id = _contact_id;
+ eo_do(contact, actual_id = ecordova_contact_id_get());
+ ck_assert_int_eq(expected_id, actual_id);
+
+ Ecordova_ContactName *contact_name = NULL;
+ eo_do(contact, contact_name = ecordova_contact_name_get());
+ fail_unless(!!contact_name);
+
+ const char *actual_given_name, *expected_given_name = _contact_name;
+ eo_do(contact_name, actual_given_name = ecordova_contactname_given_name_get());
+ ck_assert_str_eq(expected_given_name, actual_given_name);
+
+ eo_unref(contact);
+ eo_unref(contacts);
+}
+END_TEST
+
+START_TEST(find_by_name)
+{
+ Ecordova_Contacts *contacts = eo_add(ECORDOVA_CONTACTS_CLASS, NULL);
+ fail_if(NULL == contacts);
+
+ Ecordova_Contact *contact = NULL;
+ bool error = false;
+ bool timeout = false;
+
+ Ecore_Timer *timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+ eo_do(contacts, eo_event_callback_add(ECORDOVA_CONTACTS_EVENT_FIND_SUCCESS, _find_one_contact_success_cb, &contact));
+ eo_do(contacts, eo_event_callback_add(ECORDOVA_CONTACTS_EVENT_ERROR, _error_cb, &error));
+
+ Eina_List *fields = eina_list_append(NULL, "name");
+ Ecordova_Contacts_FindOptions options = {
+ .filter = "test",
+ .multiple = false
+ };
+ eo_do(contacts, ecordova_contacts_find(fields, &options));
+
+ ecore_main_loop_begin();
+
+ eina_list_free(fields);
+
+ eo_unref(timer);
+
+ fail_unless(!!contact);
+ fail_if(error);
+ fail_if(timeout);
+
+ int actual_id, expected_id = _contact_id;
+ eo_do(contact, actual_id = ecordova_contact_id_get());
+ ck_assert_int_eq(expected_id, actual_id);
+
+ Ecordova_ContactName *contact_name = NULL;
+ eo_do(contact, contact_name = ecordova_contact_name_get());
+ fail_unless(!!contact_name);
+
+ const char *actual_given_name, *expected_given_name = _contact_name;
+ eo_do(contact_name, actual_given_name = ecordova_contactname_given_name_get());
+ ck_assert_str_eq(expected_given_name, actual_given_name);
+
+ eo_unref(contact);
+ eo_unref(contacts);
+}
+END_TEST
+
+void
+ecordova_contacts_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, find_all);
+ tcase_add_test(tc, find_by_id);
+ tcase_add_test(tc, find_by_name);
+}
diff --git a/src/tests/ecordova/ecordova_contacts_test.h b/src/tests/ecordova/ecordova_contacts_test.h
new file mode 100644
index 0000000000..6a96318ae6
--- /dev/null
+++ b/src/tests/ecordova/ecordova_contacts_test.h
@@ -0,0 +1,9 @@
+#ifndef _ECORDOVA_CONTACTS_TEST_H
+#define _ECORDOVA_CONTACTS_TEST_H
+
+#include <Ecordova.h>
+#include <check.h>
+
+void ecordova_contacts_test(TCase *);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_device_test.c b/src/tests/ecordova/ecordova_device_test.c
new file mode 100644
index 0000000000..710b3b4e77
--- /dev/null
+++ b/src/tests/ecordova/ecordova_device_test.c
@@ -0,0 +1,100 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_device_test.h"
+#include "ecordova_suite.h"
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Ecordova_Device *
+_device_new(void)
+{
+ return eo_add(ECORDOVA_DEVICE_CLASS, NULL, ecordova_device_constructor());
+}
+
+START_TEST(smoke)
+{
+ Ecordova_Device *device = _device_new();
+ eo_unref(device);
+}
+END_TEST
+
+START_TEST(model_get)
+{
+ Ecordova_Device *device = _device_new();
+
+ const char *model = eo_do_ret(device, model, ecordova_device_model_get());
+ fail_if(NULL == model);
+
+ INF("%s", model);
+
+ eo_unref(device);
+}
+END_TEST
+
+START_TEST(platform_get)
+{
+ Ecordova_Device *device = _device_new();
+
+ const char *platform = eo_do_ret(device,
+ platform,
+ ecordova_device_platform_get());
+ fail_if(NULL == platform);
+
+ INF("%s", platform);
+
+ eo_unref(device);
+}
+END_TEST
+
+START_TEST(uuid_get)
+{
+ Ecordova_Device *device = _device_new();
+
+ const char *uuid = eo_do_ret(device, uuid, ecordova_device_uuid_get());
+ fail_if(NULL == uuid);
+
+ INF("%s", uuid);
+
+ eo_unref(device);
+}
+END_TEST
+
+START_TEST(version_get)
+{
+ Ecordova_Device *device = _device_new();
+
+ const char *version = eo_do_ret(device,
+ version,
+ ecordova_device_version_get());
+ fail_if(NULL == version);
+
+ INF("%s", version);
+
+ eo_unref(device);
+}
+END_TEST
+
+void
+ecordova_device_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, smoke);
+ tcase_add_test(tc, model_get);
+ tcase_add_test(tc, platform_get);
+ //tcase_add_test(tc, uuid_get); // disabled: returns NULL
+ tcase_add_test(tc, version_get);
+}
diff --git a/src/tests/ecordova/ecordova_device_test.h b/src/tests/ecordova/ecordova_device_test.h
new file mode 100644
index 0000000000..7d943cc323
--- /dev/null
+++ b/src/tests/ecordova/ecordova_device_test.h
@@ -0,0 +1,9 @@
+#ifndef _ECORDOVA_DEVICE_TEST_H
+#define _ECORDOVA_DEVICE_TEST_H
+
+#include <Ecordova.h>
+#include <check.h>
+
+void ecordova_device_test(TCase *);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_devicemotion_test.c b/src/tests/ecordova/ecordova_devicemotion_test.c
new file mode 100644
index 0000000000..fec15b5538
--- /dev/null
+++ b/src/tests/ecordova/ecordova_devicemotion_test.c
@@ -0,0 +1,89 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_devicemotion_test.h"
+#include "ecordova_suite.h"
+
+#include <stdbool.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Ecordova_Device *
+_devicemotion_new(void)
+{
+ return eo_add(ECORDOVA_DEVICEMOTION_CLASS,
+ NULL,
+ ecordova_devicemotion_constructor());
+}
+
+START_TEST(smoke)
+{
+ Ecordova_Device *devicemotion = _devicemotion_new();
+ eo_unref(devicemotion);
+}
+END_TEST
+
+static Eina_Bool
+_current_acceleration_get_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ bool *called = data;
+ *called = true;
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_error_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ bool *error = data;
+ *error = true;
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+START_TEST(current_acceleration_get)
+{
+ Ecordova_Device *devicemotion = _devicemotion_new();
+
+ bool success_event_called = false;
+ bool error_event_called = false;
+ eo_do(devicemotion, eo_event_callback_add(ECORDOVA_DEVICEMOTION_EVENT_CURRENT_SUCCESS, _current_acceleration_get_cb, &success_event_called));
+ eo_do(devicemotion, eo_event_callback_add(ECORDOVA_DEVICEMOTION_EVENT_ERROR, _error_cb, &error_event_called));
+ eo_do(devicemotion, ecordova_devicemotion_current_acceleration_get());
+
+ if (!success_event_called && !error_event_called)
+ ecore_main_loop_begin();
+
+ fail_if(error_event_called);
+ fail_unless(success_event_called);
+
+ eo_unref(devicemotion);
+}
+END_TEST
+
+void
+ecordova_devicemotion_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, smoke);
+ //tcase_add_test(tc, current_acceleration_get); // disabled: not supported
+}
diff --git a/src/tests/ecordova/ecordova_devicemotion_test.h b/src/tests/ecordova/ecordova_devicemotion_test.h
new file mode 100644
index 0000000000..dcc3d6ce9a
--- /dev/null
+++ b/src/tests/ecordova/ecordova_devicemotion_test.h
@@ -0,0 +1,9 @@
+#ifndef _ECORDOVA_DEVICEMOTION_TEST_H
+#define _ECORDOVA_DEVICEMOTION_TEST_H
+
+#include <Ecordova.h>
+#include <check.h>
+
+void ecordova_devicemotion_test(TCase *);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_deviceorientation_test.c b/src/tests/ecordova/ecordova_deviceorientation_test.c
new file mode 100644
index 0000000000..df814eb19c
--- /dev/null
+++ b/src/tests/ecordova/ecordova_deviceorientation_test.c
@@ -0,0 +1,89 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_deviceorientation_test.h"
+#include "ecordova_suite.h"
+
+#include <stdbool.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Ecordova_Device *
+_deviceorientation_new(void)
+{
+ return eo_add(ECORDOVA_DEVICEORIENTATION_CLASS,
+ NULL,
+ ecordova_deviceorientation_constructor());
+}
+
+START_TEST(smoke)
+{
+ Ecordova_Device *deviceorientation = _deviceorientation_new();
+ eo_unref(deviceorientation);
+}
+END_TEST
+
+static Eina_Bool
+_current_heading_get_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ bool *called = data;
+ *called = true;
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_error_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ bool *error = data;
+ *error = true;
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+START_TEST(current_heading_get)
+{
+ Ecordova_Device *deviceorientation = _deviceorientation_new();
+
+ bool success_event_called = false;
+ bool error_event_called = false;
+ eo_do(deviceorientation, eo_event_callback_add(ECORDOVA_DEVICEORIENTATION_EVENT_CURRENT_SUCCESS, _current_heading_get_cb, &success_event_called));
+ eo_do(deviceorientation, eo_event_callback_add(ECORDOVA_DEVICEORIENTATION_EVENT_ERROR, _error_cb, &error_event_called));
+ eo_do(deviceorientation, ecordova_deviceorientation_current_heading_get());
+
+ if (!success_event_called && !error_event_called)
+ ecore_main_loop_begin();
+
+ fail_if(error_event_called);
+ fail_unless(success_event_called);
+
+ eo_unref(deviceorientation);
+}
+END_TEST
+
+void
+ecordova_deviceorientation_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, smoke);
+ //tcase_add_test(tc, current_heading_get); // disabled: not supported
+}
diff --git a/src/tests/ecordova/ecordova_deviceorientation_test.h b/src/tests/ecordova/ecordova_deviceorientation_test.h
new file mode 100644
index 0000000000..12249a9bfd
--- /dev/null
+++ b/src/tests/ecordova/ecordova_deviceorientation_test.h
@@ -0,0 +1,9 @@
+#ifndef _ECORDOVA_DEVICEORIENTATION_TEST_H
+#define _ECORDOVA_DEVICEORIENTATION_TEST_H
+
+#include <Ecordova.h>
+#include <check.h>
+
+void ecordova_deviceorientation_test(TCase *);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_directoryentry_test.c b/src/tests/ecordova/ecordova_directoryentry_test.c
new file mode 100644
index 0000000000..51477cd5b8
--- /dev/null
+++ b/src/tests/ecordova/ecordova_directoryentry_test.c
@@ -0,0 +1,434 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_directoryentry_test.h"
+#include "ecordova_entry_test.h"
+#include "ecordova_suite.h"
+
+#include <Eio.h>
+
+#include <stdbool.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+Ecordova_DirectoryEntry *
+directoryentry_new(const char *name,
+ const char *path,
+ const char *url)
+{
+ return eo_add(ECORDOVA_DIRECTORYENTRY_CLASS,
+ NULL,
+ ecordova_directoryentry_constructor(name, path, NULL, url));
+}
+
+void
+check_exists(const char *url)
+{
+ Eina_Bool ret = ecore_file_exists(url);
+ ck_assert_int_eq(EINA_TRUE, ret);
+}
+
+void
+check_doesnt_exist(const char *url)
+{
+ Eina_Bool ret = ecore_file_exists(url);
+ ck_assert_int_eq(EINA_FALSE, ret);
+}
+
+Ecordova_DirectoryEntry *
+_create_tmpdir(Eina_Tmpstr **tmpdir)
+{
+ Eina_Bool tmpdir_created = eina_file_mkdtemp("directoryentry_test_XXXXXX", tmpdir);
+ ck_assert_int_eq(EINA_TRUE, tmpdir_created);
+ check_exists(*tmpdir);
+
+ const char *last_path_separator = strrchr(*tmpdir, '/');
+ fail_if(NULL == last_path_separator);
+
+ const char *name = last_path_separator + 1;
+ size_t len = last_path_separator - *tmpdir;
+ char path[len + 1];
+ strncpy(path, *tmpdir, len);
+ path[len] = '\0';
+
+ return directoryentry_new(name, path, *tmpdir);
+}
+
+START_TEST(smoke)
+{
+ Ecordova_DirectoryEntry *directory_entry =
+ directoryentry_new("", TESTS_BUILD_DIR, TESTS_BUILD_DIR);
+ eo_unref(directory_entry);
+}
+END_TEST
+
+Eina_Bool
+_timeout_cb(void *data)
+{
+ bool *timeout = data;
+ *timeout = true;
+ ecore_main_loop_quit();
+ return ECORE_CALLBACK_CANCEL;
+}
+
+Eina_Bool
+_entry_get_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ Ecordova_Entry **entry = data;
+ fail_if(NULL == event_info);
+
+ *entry = eo_ref((Ecordova_Entry*)event_info);
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+Eina_Bool
+_error_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ bool *error = data;
+ Ecordova_FileError *error_code = event_info;
+ fail_if(NULL == error_code);
+
+ *error = true;
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+void
+_check_entry_name(Ecordova_Entry *entry, const char *expected_name)
+{
+ const char *actual_name = eo_do_ret(entry,
+ actual_name,
+ ecordova_entry_name_get());
+ fail_if(NULL == actual_name);
+ ck_assert_str_eq(expected_name, actual_name);
+}
+
+void
+_check_entry_path(Ecordova_Entry *entry, const char *expected_path)
+{
+ const char *actual_path = eo_do_ret(entry,
+ actual_path,
+ ecordova_entry_path_get());
+ fail_if(NULL == actual_path);
+ ck_assert_str_eq(expected_path, actual_path);
+}
+
+static void
+_check_entry_is_file(Ecordova_Entry *entry)
+{
+ Eina_Bool is_file;
+ Eina_Bool is_directory;
+ eo_do(entry,
+ is_file = ecordova_entry_file_is_get(),
+ is_directory = ecordova_entry_directory_is_get());
+ fail_unless(is_file);
+ fail_if(is_directory);
+}
+
+static void
+_check_entry_is_directory(Ecordova_Entry *entry)
+{
+ Eina_Bool is_directory;
+ Eina_Bool is_file;
+ eo_do(entry,
+ is_directory = ecordova_entry_directory_is_get(),
+ is_file = ecordova_entry_file_is_get());
+ fail_unless(is_directory);
+ fail_if(is_file);
+}
+
+static bool
+_entry_get(Ecordova_Entry *obj,
+ const char *url,
+ Ecordova_FileFlags flags,
+ Ecordova_Entry **entry,
+ const Eo_Event_Description *get_event,
+ void(*entry_get)(const char *, Ecordova_FileFlags))
+{
+ *entry = NULL;
+ bool error = false;
+ bool timeout = false;
+
+ Ecore_Timer *timeout_timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+
+ eo_do(obj, eo_event_callback_add(get_event, _entry_get_cb, entry),
+ eo_event_callback_add(ECORDOVA_ENTRY_EVENT_ERROR, _error_cb, &error),
+ entry_get(url, flags));
+
+ ecore_main_loop_begin();
+
+ eo_do(obj, eo_event_callback_del(get_event, _entry_get_cb, entry),
+ eo_event_callback_del(ECORDOVA_ENTRY_EVENT_ERROR, _error_cb, &error));
+
+ eo_unref(timeout_timer);
+
+ fail_if(timeout);
+
+ return error;
+}
+
+bool
+fileentry_get(Ecordova_DirectoryEntry *directory_entry,
+ const char *url,
+ Ecordova_FileFlags flags,
+ Ecordova_FileEntry **entry)
+{
+ DBG("Getting file entry: %s", url);
+ return _entry_get(directory_entry,
+ url,
+ flags,
+ (Ecordova_Entry**)entry,
+ ECORDOVA_DIRECTORYENTRY_EVENT_FILE_GET,
+ ecordova_directoryentry_file_get);
+}
+
+bool
+directoryentry_get(Ecordova_DirectoryEntry *directory_entry,
+ const char *url,
+ Ecordova_FileFlags flags,
+ Ecordova_DirectoryEntry **entry)
+{
+ DBG("Getting directory entry: %s", url);
+ return _entry_get(directory_entry,
+ url,
+ flags,
+ (Ecordova_Entry**)entry,
+ ECORDOVA_DIRECTORYENTRY_EVENT_DIRECTORY_GET,
+ ecordova_directoryentry_directory_get);
+}
+
+START_TEST(get_file)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ const char *filename = "file.txt";
+ const char *filepath = tmpdir;
+ size_t len = strlen(filepath) + 1 + strlen(filename) + 1;
+ char fileurl[len];
+ snprintf(fileurl, len, "%s/%s", tmpdir, filename);
+
+ Ecordova_FileEntry *file_entry = NULL;
+ bool error = false;
+
+ // create exclusive
+ Ecordova_FileFlags flags = ECORDOVA_FILEFLAGS_CREATE | ECORDOVA_FILEFLAGS_EXCLUSIVE;
+ error = fileentry_get(directory_entry, filename, flags, &file_entry);
+ fail_if(error);
+ fail_unless(NULL != file_entry);
+ check_exists(fileurl);
+
+ _check_entry_is_file(file_entry);
+ _check_entry_name(file_entry, filename);
+ _check_entry_path(file_entry, filepath);
+
+ eo_unref(file_entry);
+
+
+ // create exclusive on a existing file is an error
+ flags = ECORDOVA_FILEFLAGS_CREATE | ECORDOVA_FILEFLAGS_EXCLUSIVE;
+ error = fileentry_get(directory_entry, filename, flags, &file_entry);
+ fail_if(NULL != file_entry);
+ fail_unless(error);
+
+
+ // just create on an existing file opens it
+ flags = ECORDOVA_FILEFLAGS_CREATE;
+ error = fileentry_get(directory_entry, filename, flags, &file_entry);
+ fail_if(error);
+ fail_unless(NULL != file_entry);
+
+ _check_entry_is_file(file_entry);
+ _check_entry_name(file_entry, filename);
+ _check_entry_path(file_entry, filepath);
+
+ eo_unref(file_entry);
+
+ // just opens it
+ flags = 0;
+ error = fileentry_get(directory_entry, filename, flags, &file_entry);
+ fail_if(error);
+ fail_unless(NULL != file_entry);
+
+ _check_entry_is_file(file_entry);
+ _check_entry_name(file_entry, filename);
+ _check_entry_path(file_entry, filepath);
+
+ fail_if(error = entry_remove(file_entry));
+ eo_unref(file_entry);
+
+ // error on non existent file
+ flags = 0;
+ error = fileentry_get(directory_entry, ",**??non_existent??**,", flags, &file_entry);
+ fail_if(NULL != file_entry);
+ fail_unless(error);
+
+ fail_if(error = entry_remove(directory_entry));
+ eo_unref(directory_entry);
+
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+START_TEST(get_dir)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ const char *dir_name = "some_path";
+ const char *dir_path = tmpdir;
+ size_t len = strlen(dir_path) + 1 + strlen(dir_name) + 1;
+ char dir_url[len];
+ snprintf(dir_url, len, "%s/%s", tmpdir, dir_name);
+
+ Ecordova_DirectoryEntry *child_entry = NULL;
+ bool error = false;
+
+ // create exclusive
+ Ecordova_FileFlags flags = ECORDOVA_FILEFLAGS_CREATE | ECORDOVA_FILEFLAGS_EXCLUSIVE;
+ error = directoryentry_get(directory_entry, dir_name, flags, &child_entry);
+ fail_if(error);
+ fail_unless(NULL != child_entry);
+ check_exists(dir_url);
+
+ _check_entry_is_directory(child_entry);
+ _check_entry_name(child_entry, dir_name);
+ _check_entry_path(child_entry, dir_path);
+
+ eo_unref(child_entry);
+
+
+ // create exclusive on a existing directory is an error
+ flags = ECORDOVA_FILEFLAGS_CREATE | ECORDOVA_FILEFLAGS_EXCLUSIVE;
+ error = directoryentry_get(directory_entry, dir_name, flags, &child_entry);
+ fail_if(NULL != child_entry);
+ fail_unless(error);
+
+
+ // just the create flag on an existing directory opens it
+ flags = ECORDOVA_FILEFLAGS_CREATE;
+ error = directoryentry_get(directory_entry, dir_name, flags, &child_entry);
+ fail_if(error);
+ fail_unless(NULL != child_entry);
+
+ _check_entry_is_directory(child_entry);
+ _check_entry_name(child_entry, dir_name);
+ _check_entry_path(child_entry, dir_path);
+
+ eo_unref(child_entry);
+
+ // just opens it
+ flags = 0;
+ error = directoryentry_get(directory_entry, dir_name, flags, &child_entry);
+ fail_if(error);
+ fail_unless(NULL != child_entry);
+
+ _check_entry_is_directory(child_entry);
+ _check_entry_name(child_entry, dir_name);
+ _check_entry_path(child_entry, dir_path);
+
+ fail_if(error = entry_remove(child_entry));
+ eo_unref(child_entry);
+
+
+ // error on non existent directory
+ flags = 0;
+ error = directoryentry_get(directory_entry, ",**??non_existent??**,", flags, &child_entry);
+ fail_if(NULL != child_entry);
+ fail_unless(error);
+
+
+ fail_if(error = entry_remove(directory_entry));
+ eo_unref(directory_entry);
+
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+static bool
+_directoryentry_recursively_remove(Ecordova_DirectoryEntry *directory_entry)
+{
+ return entry_do(directory_entry,
+ ECORDOVA_DIRECTORYENTRY_EVENT_REMOVE_SUCCESS,
+ ecordova_directoryentry_recursively_remove);
+}
+
+START_TEST(remove_recursively)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ // removes an existent directory recursively
+ const char *child_name = "child";
+ size_t len = strlen(tmpdir) + 1 + strlen(child_name) + 1;
+ char child_dir[len];
+ snprintf(child_dir, len, "%s/%s", tmpdir, child_name);
+
+ Eina_Bool ret = ecore_file_mkdir(child_dir);
+ ck_assert_int_eq(EINA_TRUE, ret);
+
+ bool error = _directoryentry_recursively_remove(directory_entry);
+ fail_if(error);
+
+ check_doesnt_exist(child_dir);
+ check_doesnt_exist(tmpdir);
+
+ // error on non existent directory
+ error = _directoryentry_recursively_remove(directory_entry);
+ fail_unless(error);
+
+ eo_unref(directory_entry);
+
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+START_TEST(create_reader)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ Ecordova_DirectoryReader *directory_reader =
+ eo_do_ret(directory_entry,
+ directory_reader,
+ ecordova_directoryentry_reader_create());
+ fail_if(NULL == directory_reader);
+ eo_unref(directory_reader);
+
+ bool error = false;
+ fail_if(error = entry_remove(directory_entry));
+ eo_unref(directory_entry);
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+void
+ecordova_directoryentry_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, smoke);
+ tcase_add_test(tc, get_file);
+ tcase_add_test(tc, get_dir);
+ tcase_add_test(tc, remove_recursively);
+ tcase_add_test(tc, create_reader);
+}
diff --git a/src/tests/ecordova/ecordova_directoryentry_test.h b/src/tests/ecordova/ecordova_directoryentry_test.h
new file mode 100644
index 0000000000..7220400550
--- /dev/null
+++ b/src/tests/ecordova/ecordova_directoryentry_test.h
@@ -0,0 +1,24 @@
+#ifndef _ECORDOVA_DIRECTORYENTRY_TEST_H
+#define _ECORDOVA_DIRECTORYENTRY_TEST_H
+
+#include <Ecordova.h>
+
+#include <Ecore_File.h>
+
+#include <check.h>
+
+#include <stdbool.h>
+
+void ecordova_directoryentry_test(TCase *);
+Ecordova_DirectoryEntry *_create_tmpdir(Eina_Tmpstr **);
+Eina_Bool _timeout_cb(void *);
+Eina_Bool _entry_get_cb(void *, Eo *, const Eo_Event_Description *, void *);
+Eina_Bool _error_cb(void *, Eo *, const Eo_Event_Description *, void *);
+
+bool directoryentry_get(Ecordova_DirectoryEntry *directory_entry, const char *, Ecordova_FileFlags, Ecordova_DirectoryEntry **);
+bool fileentry_get(Ecordova_DirectoryEntry *directory_entry, const char *, Ecordova_FileFlags, Ecordova_FileEntry **);
+void check_exists(const char *url);
+void check_doesnt_exist(const char *url);
+Ecordova_DirectoryEntry *directoryentry_new(const char *, const char *, const char *);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_directoryreader_test.c b/src/tests/ecordova/ecordova_directoryreader_test.c
new file mode 100644
index 0000000000..2e08dff327
--- /dev/null
+++ b/src/tests/ecordova/ecordova_directoryreader_test.c
@@ -0,0 +1,132 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_directoryreader_test.h"
+#include "ecordova_suite.h"
+
+#include <stdbool.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+
+static Ecordova_DirectoryReader *
+_directoryreader_new(const char *path)
+{
+ return eo_add(ECORDOVA_DIRECTORYREADER_CLASS,
+ NULL,
+ ecordova_directoryreader_constructor(path));
+}
+
+START_TEST(smoke)
+{
+ Ecordova_DirectoryReader *directory_reader = _directoryreader_new(TESTS_BUILD_DIR);
+ eo_unref(directory_reader);
+}
+END_TEST
+
+static Eina_Bool
+_timeout_cb(void *data)
+{
+ bool *timeout = data;
+ *timeout = true;
+ ecore_main_loop_quit();
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_success_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ bool *success = data;
+ Eina_List *entries = event_info;
+ fail_if(NULL == entries);
+
+ *success = true;
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+static Eina_Bool
+_error_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ bool *error = data;
+ Ecordova_FileError *error_code = event_info;
+ fail_if(NULL == error_code);
+
+ *error = true;
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+START_TEST(read_entries_success)
+{
+ Ecordova_DirectoryReader *directory_reader = _directoryreader_new(TESTS_BUILD_DIR);
+
+ bool success = false;
+ bool error = false;
+ bool timeout = false;
+
+ Ecore_Timer *timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+ eo_do(directory_reader, eo_event_callback_add(ECORDOVA_DIRECTORYREADER_EVENT_SUCCESS, _success_cb, &success));
+ eo_do(directory_reader, eo_event_callback_add(ECORDOVA_DIRECTORYREADER_EVENT_ERROR, _error_cb, &error));
+ eo_do(directory_reader, ecordova_directoryreader_entries_read());
+ ecore_main_loop_begin();
+
+ eo_unref(timer);
+ fail_if(error);
+ fail_if(timeout);
+ fail_unless(success);
+
+ eo_unref(directory_reader);
+}
+END_TEST
+
+START_TEST(read_entries_error)
+{
+ Ecordova_DirectoryReader *directory_reader = _directoryreader_new("/**??this_directory_doesn't_exist??**");
+
+ bool success = false;
+ bool error = false;
+ bool timeout = false;
+
+ Ecore_Timer *timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+ eo_do(directory_reader, eo_event_callback_add(ECORDOVA_DIRECTORYREADER_EVENT_SUCCESS, _success_cb, &success));
+ eo_do(directory_reader, eo_event_callback_add(ECORDOVA_DIRECTORYREADER_EVENT_ERROR, _error_cb, &error));
+ eo_do(directory_reader, ecordova_directoryreader_entries_read());
+ ecore_main_loop_begin();
+
+ eo_unref(timer);
+ fail_if(success);
+ fail_if(timeout);
+ fail_unless(error);
+
+ eo_unref(directory_reader);
+}
+END_TEST
+
+void
+ecordova_directoryreader_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, smoke);
+ tcase_add_test(tc, read_entries_success);
+ tcase_add_test(tc, read_entries_error);
+}
diff --git a/src/tests/ecordova/ecordova_directoryreader_test.h b/src/tests/ecordova/ecordova_directoryreader_test.h
new file mode 100644
index 0000000000..e01bad91e4
--- /dev/null
+++ b/src/tests/ecordova/ecordova_directoryreader_test.h
@@ -0,0 +1,9 @@
+#ifndef _ECORDOVA_DIRECTORYREADER_TEST_H
+#define _ECORDOVA_DIRECTORYREADER_TEST_H
+
+#include <Ecordova.h>
+#include <check.h>
+
+void ecordova_directoryreader_test(TCase *);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_entry_test.c b/src/tests/ecordova/ecordova_entry_test.c
new file mode 100644
index 0000000000..49d9c72479
--- /dev/null
+++ b/src/tests/ecordova/ecordova_entry_test.c
@@ -0,0 +1,748 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_entry_test.h"
+#include "ecordova_directoryentry_test.h"
+#include "ecordova_suite.h"
+
+#include <Eio.h>
+
+#include <stdbool.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+START_TEST(smoke)
+{
+ Ecordova_Entry *entry = eo_add(ECORDOVA_ENTRY_CLASS,
+ NULL,
+ ecordova_entry_constructor(EINA_FALSE,
+ EINA_TRUE,
+ "",
+ TESTS_BUILD_DIR,
+ NULL,
+ TESTS_BUILD_DIR));
+ eo_unref(entry);
+}
+END_TEST
+
+static bool
+_move_copy_to(Ecordova_Entry *source,
+ Ecordova_Entry *parent_dest,
+ const char *new_name,
+ Ecordova_Entry **entry,
+ const Eo_Event_Description *event_desc,
+ void(*method)(Ecordova_DirectoryEntry*, const char *))
+{
+ *entry = NULL;
+ bool error = false;
+ bool timeout = false;
+
+ Ecore_Timer *timeout_timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+
+ eo_do(source, eo_event_callback_add(event_desc, _entry_get_cb, entry),
+ eo_event_callback_add(ECORDOVA_ENTRY_EVENT_ERROR, _error_cb, &error),
+ method(parent_dest, new_name));
+
+ ecore_main_loop_begin();
+
+ eo_do(source, eo_event_callback_del(event_desc, _entry_get_cb, entry),
+ eo_event_callback_del(ECORDOVA_ENTRY_EVENT_ERROR, _error_cb, &error));
+
+ eo_unref(timeout_timer);
+
+ fail_if(timeout);
+
+ return error;
+}
+
+static bool
+_move_to(Ecordova_Entry *source,
+ Ecordova_Entry *parent_dest,
+ const char *new_name,
+ Ecordova_Entry **moved_entry)
+{
+ return _move_copy_to(source,
+ parent_dest,
+ new_name,
+ moved_entry,
+ ECORDOVA_ENTRY_EVENT_MOVE_SUCCESS,
+ ecordova_entry_move);
+}
+
+static bool
+_copy_to(Ecordova_Entry *source,
+ Ecordova_Entry *parent_dest,
+ const char *new_name,
+ Ecordova_Entry **copied_entry)
+{
+ return _move_copy_to(source,
+ parent_dest,
+ new_name,
+ copied_entry,
+ ECORDOVA_ENTRY_EVENT_COPY_SUCCESS,
+ ecordova_entry_copy);
+}
+
+Eina_Bool
+_do_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ bool *removed = data;
+ fail_if(NULL != event_info);
+
+ *removed = true;
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+bool
+entry_do(Ecordova_Entry *entry,
+ const Eo_Event_Description *event_desc,
+ void(*method)())
+{
+ bool success = false;
+ bool error = false;
+ bool timeout = false;
+
+ Ecore_Timer *timeout_timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+
+ eo_do(entry, eo_event_callback_add(event_desc, _do_cb, &success),
+ eo_event_callback_add(ECORDOVA_ENTRY_EVENT_ERROR, _error_cb, &error),
+ method());
+
+ ecore_main_loop_begin();
+
+ eo_do(entry, eo_event_callback_del(event_desc, _do_cb, &success),
+ eo_event_callback_del(ECORDOVA_ENTRY_EVENT_ERROR, _error_cb, &error));
+
+ eo_unref(timeout_timer);
+
+ fail_if(timeout);
+
+ return error || !success;
+}
+
+static bool
+_entry_parent_get(Ecordova_Entry *obj, Ecordova_Entry **parent)
+{
+ *parent = NULL;
+ bool error = false;
+ bool timeout = false;
+
+ Ecore_Timer *timeout_timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+
+ eo_do(obj, eo_event_callback_add(ECORDOVA_ENTRY_EVENT_PARENT_GET, _entry_get_cb, parent),
+ eo_event_callback_add(ECORDOVA_ENTRY_EVENT_ERROR, _error_cb, &error),
+ ecordova_entry_parent_get());
+
+ ecore_main_loop_begin();
+
+ eo_do(obj, eo_event_callback_del(ECORDOVA_ENTRY_EVENT_PARENT_GET, _entry_get_cb, parent),
+ eo_event_callback_del(ECORDOVA_ENTRY_EVENT_ERROR, _error_cb, &error));
+
+ eo_unref(timeout_timer);
+
+ fail_if(timeout);
+
+ return error;
+}
+
+Eina_Bool
+_metadata_get_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ Ecordova_Metadata *metadata = data;
+ fail_if(NULL == event_info);
+
+ *metadata = *(Ecordova_Metadata*)event_info;
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+static bool
+_entry_metadataget(Ecordova_Entry *obj, Ecordova_Metadata *metadata)
+{
+ *metadata = (Ecordova_Metadata){0};
+ bool error = false;
+ bool timeout = false;
+
+ Ecore_Timer *timeout_timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+
+ eo_do(obj, eo_event_callback_add(ECORDOVA_ENTRY_EVENT_METADATA_GET, _metadata_get_cb, metadata),
+ eo_event_callback_add(ECORDOVA_ENTRY_EVENT_ERROR, _error_cb, &error),
+ ecordova_entry_metadata_get());
+
+ ecore_main_loop_begin();
+
+ eo_do(obj, eo_event_callback_del(ECORDOVA_ENTRY_EVENT_METADATA_GET, _metadata_get_cb, metadata),
+ eo_event_callback_del(ECORDOVA_ENTRY_EVENT_ERROR, _error_cb, &error));
+
+ eo_unref(timeout_timer);
+
+ fail_if(timeout);
+
+ return error;
+}
+
+bool
+entry_remove(Ecordova_Entry *entry)
+{
+ return entry_do(entry,
+ ECORDOVA_ENTRY_EVENT_REMOVE_SUCCESS,
+ ecordova_entry_remove);
+}
+
+START_TEST(dir_remove)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ const char *filename = "file.txt";
+ size_t len = strlen(tmpdir) + 1 + strlen(filename) + 1;
+ char file_url[len];
+ snprintf(file_url, len, "%s/%s", tmpdir, filename);
+
+
+ bool error = false;
+
+ Ecordova_FileEntry *file_entry = NULL;
+ const Ecordova_FileFlags flags = ECORDOVA_FILEFLAGS_CREATE | ECORDOVA_FILEFLAGS_EXCLUSIVE;
+ error = fileentry_get(directory_entry, file_url, flags, &file_entry);
+ fail_if(error);
+ fail_unless(NULL != file_entry);
+ check_exists(file_url);
+
+ // non empty directory cannot be removed, gives error
+ fail_unless(error = entry_remove(directory_entry));
+
+ // turns the directory empty
+ fail_if(error = entry_remove(file_entry));
+
+ // removes the directory
+ fail_if(error = entry_remove(directory_entry));
+
+ // non existent directory gives error
+ fail_unless(error = entry_remove(directory_entry));
+
+ eo_unref(file_entry);
+ eo_unref(directory_entry);
+
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+START_TEST(dir_move_to)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ const char *child_name1 = "child1";
+ size_t len = strlen(tmpdir) + 1 + strlen(child_name1) + 1;
+ char child_dir1[len];
+ snprintf(child_dir1, len, "%s/%s", tmpdir, child_name1);
+ Eina_Bool ret = ecore_file_mkdir(child_dir1);
+ ck_assert_int_eq(EINA_TRUE, ret);
+
+ const char *child_name2 = "child2";
+ len = strlen(tmpdir) + 1 + strlen(child_name2) + 1;
+ char child_dir2[len];
+ snprintf(child_dir2, len, "%s/%s", tmpdir, child_name2);
+ ret = ecore_file_mkdir(child_dir2);
+ ck_assert_int_eq(EINA_TRUE, ret);
+
+ Ecordova_DirectoryEntry *child_entry1 = NULL;
+ Ecordova_DirectoryEntry *child_entry2 = NULL;
+ bool error = false;
+
+ error = directoryentry_get(directory_entry, child_dir1, 0, &child_entry1);
+ fail_if(error);
+ fail_unless(NULL != child_entry1);
+ error = directoryentry_get(directory_entry, child_dir2, 0, &child_entry2);
+ fail_if(error);
+ fail_unless(NULL != child_entry2);
+
+ Ecordova_DirectoryEntry *moved_entry = NULL;
+ error = _move_to(child_entry1, child_entry2, NULL, &moved_entry);
+ fail_if(error);
+ fail_unless(NULL != moved_entry);
+
+ fail_if(error = entry_remove(moved_entry));
+ fail_if(error = entry_remove(child_entry2));
+ fail_if(error = entry_remove(directory_entry));
+
+ eo_unref(moved_entry);
+ eo_unref(child_entry2);
+ eo_unref(child_entry1);
+ eo_unref(directory_entry);
+
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+START_TEST(dir_rename)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ const char *child_name = "child";
+ size_t len = strlen(tmpdir) + 1 + strlen(child_name) + 1;
+ char child_dir[len];
+ snprintf(child_dir, len, "%s/%s", tmpdir, child_name);
+ Eina_Bool ret = ecore_file_mkdir(child_dir);
+ ck_assert_int_eq(EINA_TRUE, ret);
+
+ Ecordova_DirectoryEntry *child_entry = NULL;
+ bool error = false;
+
+ error = directoryentry_get(directory_entry, child_dir, 0, &child_entry);
+ fail_if(error);
+ fail_unless(NULL != child_entry);
+
+ Ecordova_DirectoryEntry *renamed_entry = NULL;
+ error = _move_to(child_entry, directory_entry, "renamed", &renamed_entry);
+ fail_if(error);
+ fail_unless(NULL != renamed_entry);
+
+ fail_if(error = entry_remove(renamed_entry));
+ fail_if(error = entry_remove(directory_entry));
+
+ eo_unref(renamed_entry);
+ eo_unref(child_entry);
+ eo_unref(directory_entry);
+
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+START_TEST(dir_copy)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ const char *child_name = "child";
+ size_t len = strlen(tmpdir) + 1 + strlen(child_name) + 1;
+ char child_dir[len];
+ snprintf(child_dir, len, "%s/%s", tmpdir, child_name);
+ Eina_Bool ret = ecore_file_mkdir(child_dir);
+ ck_assert_int_eq(EINA_TRUE, ret);
+
+ const char *filename = "file.txt";
+ len = strlen(child_dir) + 1 + strlen(filename) + 1;
+ char file_url[len];
+ snprintf(file_url, len, "%s/%s", child_dir, filename);
+
+ bool error = false;
+
+ Ecordova_FileEntry *file_entry = NULL;
+ const Ecordova_FileFlags flags = ECORDOVA_FILEFLAGS_CREATE | ECORDOVA_FILEFLAGS_EXCLUSIVE;
+ error = fileentry_get(directory_entry, file_url, flags, &file_entry);
+ fail_if(error);
+ fail_unless(NULL != file_entry);
+ check_exists(file_url);
+
+ Ecordova_DirectoryEntry *child_entry = NULL;
+
+ error = directoryentry_get(directory_entry, child_dir, 0, &child_entry);
+ fail_if(error);
+ fail_unless(NULL != child_entry);
+
+ const char *NEW_DIR_NAME = "copied";
+ Ecordova_DirectoryEntry *copied_dir_entry = NULL;
+ error = _copy_to(child_entry, directory_entry, NEW_DIR_NAME, &copied_dir_entry);
+ fail_if(error);
+ fail_unless(NULL != copied_dir_entry);
+
+ len = strlen(tmpdir) + 1 + strlen(NEW_DIR_NAME) + 1 + strlen(filename) + 1;
+ char copied_file_url[len];
+ snprintf(copied_file_url, len, "%s/%s/%s", tmpdir, NEW_DIR_NAME, filename);
+
+ check_exists(copied_file_url);
+ Ecordova_FileEntry *copied_file_entry = NULL;
+ error = fileentry_get(directory_entry, copied_file_url, 0, &copied_file_entry);
+ fail_if(error);
+ fail_unless(NULL != copied_file_entry);
+
+ fail_if(error = entry_remove(file_entry));
+ fail_if(error = entry_remove(child_entry));
+ fail_if(error = entry_remove(copied_file_entry));
+ fail_if(error = entry_remove(copied_dir_entry));
+ fail_if(error = entry_remove(directory_entry));
+
+ eo_unref(file_entry);
+ eo_unref(copied_file_entry);
+ eo_unref(copied_dir_entry);
+ eo_unref(child_entry);
+ eo_unref(directory_entry);
+
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+START_TEST(dir_parent)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ const char *dir_name = "child";
+ size_t len = strlen(tmpdir) + 1 + strlen(dir_name) + 1;
+ char dir_url[len];
+ snprintf(dir_url, len, "%s/%s", tmpdir, dir_name);
+
+ bool error = false;
+
+ Ecordova_FileEntry *dir_entry = NULL;
+ const Ecordova_FileFlags flags = ECORDOVA_FILEFLAGS_CREATE | ECORDOVA_FILEFLAGS_EXCLUSIVE;
+ error = directoryentry_get(directory_entry, dir_url, flags, &dir_entry);
+ fail_if(error);
+ fail_unless(NULL != dir_entry);
+ check_exists(dir_url);
+
+ Ecordova_FileEntry *parent_entry = NULL;
+ fail_if(error = _entry_parent_get(dir_entry, &parent_entry));
+
+ const char *directory_name;
+ const char *parent_name;
+ eo_do(directory_entry,
+ directory_name = ecordova_entry_name_get(),
+ parent_name = ecordova_entry_name_get());
+ fail_if(NULL == directory_name);
+ fail_if(NULL == parent_name);
+ ck_assert_str_eq(directory_name, parent_name);
+
+ fail_if(error = entry_remove(dir_entry));
+ fail_if(error = entry_remove(directory_entry));
+
+ eo_unref(parent_entry);
+ eo_unref(dir_entry);
+ eo_unref(directory_entry);
+
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+START_TEST(dir_root_parent)
+{
+ Ecordova_DirectoryEntry *directory_entry = directoryentry_new("", "/", "/");
+
+ Ecordova_FileEntry *parent_entry = NULL;
+ bool error = false;
+ fail_if(error = _entry_parent_get(directory_entry, &parent_entry));
+
+ const char *directory_name = "";
+ fail_if(NULL == directory_name);
+ const char *parent_name = eo_do_ret(parent_entry,
+ parent_name,
+ ecordova_entry_name_get());
+ fail_if(NULL == parent_name);
+ ck_assert_str_eq(directory_name, parent_name);
+
+ eo_unref(parent_entry);
+ eo_unref(directory_entry);
+}
+END_TEST
+
+START_TEST(dir_metadata)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ const char *dir_name = "child";
+ size_t len = strlen(tmpdir) + 1 + strlen(dir_name) + 1;
+ char dir_url[len];
+ snprintf(dir_url, len, "%s/%s", tmpdir, dir_name);
+
+ bool error = false;
+
+ Ecordova_FileEntry *dir_entry = NULL;
+ const Ecordova_FileFlags flags = ECORDOVA_FILEFLAGS_CREATE | ECORDOVA_FILEFLAGS_EXCLUSIVE;
+ error = fileentry_get(directory_entry, dir_url, flags, &dir_entry);
+ fail_if(error);
+ fail_unless(NULL != dir_entry);
+ check_exists(dir_url);
+
+ Ecordova_Metadata metadata = {0};
+ fail_if(error = _entry_metadataget(dir_entry, &metadata));
+ ck_assert_int_ne(0, metadata.modification_date);
+
+ fail_if(error = entry_remove(dir_entry));
+ fail_if(error = entry_remove(directory_entry));
+
+ eo_unref(dir_entry);
+ eo_unref(directory_entry);
+
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+START_TEST(file_remove)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ const char *filename = "file.txt";
+ const char *filepath = tmpdir;
+ size_t len = strlen(filepath) + 1 + strlen(filename) + 1;
+ char fileurl[len];
+ snprintf(fileurl, len, "%s/%s", tmpdir, filename);
+
+ Ecordova_FileEntry *file_entry = NULL;
+ bool error = false;
+
+ const Ecordova_FileFlags flags = ECORDOVA_FILEFLAGS_CREATE | ECORDOVA_FILEFLAGS_EXCLUSIVE;
+ error = fileentry_get(directory_entry, filename, flags, &file_entry);
+ fail_if(error);
+ fail_unless(NULL != file_entry);
+ check_exists(fileurl);
+
+ fail_if(error = entry_remove(file_entry));
+ // non existent gives error
+ fail_unless(error = entry_remove(file_entry));
+ eo_unref(file_entry);
+
+ fail_if(error = entry_remove(directory_entry));
+ eo_unref(directory_entry);
+
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+START_TEST(file_move_to)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ const char *filename = "file.txt";
+ size_t len = strlen(tmpdir) + 1 + strlen(filename) + 1;
+ char file_url[len];
+ snprintf(file_url, len, "%s/%s", tmpdir, filename);
+
+ const char *dirname = "dir";
+ len = strlen(tmpdir) + 1 + strlen(dirname) + 1;
+ char dir_url[len];
+ snprintf(dir_url, len, "%s/%s", tmpdir, dirname);
+
+ bool error = false;
+
+ Ecordova_FileEntry *file_entry = NULL;
+ const Ecordova_FileFlags flags = ECORDOVA_FILEFLAGS_CREATE | ECORDOVA_FILEFLAGS_EXCLUSIVE;
+ error = fileentry_get(directory_entry, file_url, flags, &file_entry);
+ fail_if(error);
+ fail_unless(NULL != file_entry);
+ check_exists(file_url);
+
+ Ecordova_DirectoryEntry *dir_entry = NULL;
+ error = directoryentry_get(directory_entry, dir_url, flags, &dir_entry);
+ fail_if(error);
+ fail_unless(NULL != dir_entry);
+ check_exists(dir_url);
+
+ Ecordova_FileEntry *moved_entry = NULL;
+ error = _move_to(file_entry, dir_entry, NULL, &moved_entry);
+ fail_if(error);
+ fail_unless(NULL != moved_entry);
+ check_doesnt_exist(file_url);
+
+ fail_if(error = entry_remove(moved_entry));
+ fail_if(error = entry_remove(dir_entry));
+ fail_if(error = entry_remove(directory_entry));
+
+ eo_unref(moved_entry);
+ eo_unref(dir_entry);
+ eo_unref(file_entry);
+ eo_unref(directory_entry);
+
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+START_TEST(file_rename)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ const char *filename = "file.txt";
+ size_t len = strlen(tmpdir) + 1 + strlen(filename) + 1;
+ char file_url[len];
+ snprintf(file_url, len, "%s/%s", tmpdir, filename);
+
+ bool error = false;
+
+ Ecordova_FileEntry *file_entry = NULL;
+ const Ecordova_FileFlags flags = ECORDOVA_FILEFLAGS_CREATE | ECORDOVA_FILEFLAGS_EXCLUSIVE;
+ error = fileentry_get(directory_entry, file_url, flags, &file_entry);
+ fail_if(error);
+ fail_unless(NULL != file_entry);
+ check_exists(file_url);
+
+ Ecordova_FileEntry *renamed_entry = NULL;
+ error = _move_to(file_entry, directory_entry, "renamed.txt", &renamed_entry);
+ fail_if(error);
+ fail_unless(NULL != renamed_entry);
+ check_doesnt_exist(file_url);
+
+ fail_if(error = entry_remove(renamed_entry));
+ fail_if(error = entry_remove(directory_entry));
+
+ eo_unref(renamed_entry);
+ eo_unref(file_entry);
+ eo_unref(directory_entry);
+
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+START_TEST(file_copy)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ const char *filename = "file.txt";
+ size_t len = strlen(tmpdir) + 1 + strlen(filename) + 1;
+ char file_url[len];
+ snprintf(file_url, len, "%s/%s", tmpdir, filename);
+
+ bool error = false;
+
+ Ecordova_FileEntry *file_entry = NULL;
+ const Ecordova_FileFlags flags = ECORDOVA_FILEFLAGS_CREATE | ECORDOVA_FILEFLAGS_EXCLUSIVE;
+ error = fileentry_get(directory_entry, file_url, flags, &file_entry);
+ fail_if(error);
+ fail_unless(NULL != file_entry);
+ check_exists(file_url);
+
+
+ const char *copiedfilename = "copied.txt";
+ len = strlen(tmpdir) + 1 + strlen(copiedfilename) + 1;
+ char copied_file_url[len];
+ snprintf(copied_file_url, len, "%s/%s", tmpdir, copiedfilename);
+
+ Ecordova_FileEntry *copied_entry = NULL;
+ error = _copy_to(file_entry, directory_entry, copiedfilename, &copied_entry);
+ fail_if(error);
+ fail_unless(NULL != copied_entry);
+ check_exists(copied_file_url);
+
+ fail_if(error = entry_remove(file_entry));
+ fail_if(error = entry_remove(copied_entry));
+ fail_if(error = entry_remove(directory_entry));
+
+ eo_unref(copied_entry);
+ eo_unref(file_entry);
+ eo_unref(directory_entry);
+
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+START_TEST(file_parent)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ const char *filename = "file.txt";
+ size_t len = strlen(tmpdir) + 1 + strlen(filename) + 1;
+ char file_url[len];
+ snprintf(file_url, len, "%s/%s", tmpdir, filename);
+
+ bool error = false;
+
+ Ecordova_FileEntry *file_entry = NULL;
+ const Ecordova_FileFlags flags = ECORDOVA_FILEFLAGS_CREATE | ECORDOVA_FILEFLAGS_EXCLUSIVE;
+ error = fileentry_get(directory_entry, file_url, flags, &file_entry);
+ fail_if(error);
+ fail_unless(NULL != file_entry);
+ check_exists(file_url);
+
+ Ecordova_FileEntry *parent_entry = NULL;
+ fail_if(error = _entry_parent_get(file_entry, &parent_entry));
+
+ const char *directory_name = eo_do_ret(directory_entry,
+ directory_name,
+ ecordova_entry_name_get());
+ const char *parent_name = eo_do_ret(parent_entry,
+ parent_name,
+ ecordova_entry_name_get());
+ fail_if(NULL == directory_name);
+ fail_if(NULL == parent_name);
+ ck_assert_str_eq(directory_name, parent_name);
+
+ fail_if(error = entry_remove(file_entry));
+ fail_if(error = entry_remove(directory_entry));
+
+ eo_unref(parent_entry);
+ eo_unref(file_entry);
+ eo_unref(directory_entry);
+
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+START_TEST(file_metadata)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ const char *filename = "file.txt";
+ size_t len = strlen(tmpdir) + 1 + strlen(filename) + 1;
+ char file_url[len];
+ snprintf(file_url, len, "%s/%s", tmpdir, filename);
+
+ bool error = false;
+
+ Ecordova_FileEntry *file_entry = NULL;
+ const Ecordova_FileFlags flags = ECORDOVA_FILEFLAGS_CREATE | ECORDOVA_FILEFLAGS_EXCLUSIVE;
+ error = fileentry_get(directory_entry, file_url, flags, &file_entry);
+ fail_if(error);
+ fail_unless(NULL != file_entry);
+ check_exists(file_url);
+
+ Ecordova_Metadata metadata = {0};
+ fail_if(error = _entry_metadataget(file_entry, &metadata));
+ ck_assert_int_ne(0, metadata.modification_date);
+
+ fail_if(error = entry_remove(file_entry));
+ fail_if(error = entry_remove(directory_entry));
+
+ eo_unref(file_entry);
+ eo_unref(directory_entry);
+
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+void
+ecordova_entry_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, smoke);
+ tcase_add_test(tc, dir_remove);
+ tcase_add_test(tc, dir_move_to);
+ tcase_add_test(tc, dir_rename);
+ tcase_add_test(tc, dir_copy);
+ tcase_add_test(tc, dir_parent);
+ tcase_add_test(tc, dir_root_parent);
+ tcase_add_test(tc, dir_metadata);
+ tcase_add_test(tc, file_remove);
+ tcase_add_test(tc, file_move_to);
+ tcase_add_test(tc, file_rename);
+ tcase_add_test(tc, file_copy);
+ tcase_add_test(tc, file_parent);
+ tcase_add_test(tc, file_metadata);
+}
diff --git a/src/tests/ecordova/ecordova_entry_test.h b/src/tests/ecordova/ecordova_entry_test.h
new file mode 100644
index 0000000000..ba737f3b09
--- /dev/null
+++ b/src/tests/ecordova/ecordova_entry_test.h
@@ -0,0 +1,14 @@
+#ifndef _ECORDOVA_ENTRY_TEST_H
+#define _ECORDOVA_ENTRY_TEST_H
+
+#include <Ecordova.h>
+
+#include <check.h>
+
+#include <stdbool.h>
+
+void ecordova_entry_test(TCase *);
+bool entry_remove(Ecordova_Entry *);
+bool entry_do(Ecordova_Entry *, const Eo_Event_Description *, void(*)());
+
+#endif
diff --git a/src/tests/ecordova/ecordova_file_test.c b/src/tests/ecordova/ecordova_file_test.c
new file mode 100644
index 0000000000..7696062a50
--- /dev/null
+++ b/src/tests/ecordova/ecordova_file_test.c
@@ -0,0 +1,140 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_file_test.h"
+#include "ecordova_suite.h"
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Ecordova_File *
+_file_new(const char *name,
+ const char *url,
+ const char *type,
+ time_t last_modified_date,
+ long size)
+{
+ return eo_add(ECORDOVA_FILE_CLASS,
+ NULL,
+ ecordova_file_constructor(name,
+ url,
+ type,
+ last_modified_date,
+ size));
+}
+
+START_TEST(smoke)
+{
+ Ecordova_File *file = _file_new("", "", "", 0, 0);
+ eo_unref(file);
+}
+END_TEST
+
+static void
+_check_start_end(Ecordova_File *file, long expected_start, long expected_end)
+{
+ long actual_start, actual_end;
+ eo_do(file,
+ actual_start = ecordova_file_start_get(),
+ actual_end = ecordova_file_end_get());
+ ck_assert_int_eq(expected_start, actual_start);
+ ck_assert_int_eq(expected_end, actual_end);
+}
+
+START_TEST(slice)
+{
+ const long start = 0;
+ const long size = 100;
+ Ecordova_File *file = _file_new("", "", "", 0, size);
+ _check_start_end(file, start, size);
+
+
+ {
+ // normal slice
+ Ecordova_File *sliced_file = eo_do_ret(file,
+ sliced_file,
+ ecordova_file_slice(50, 70));
+ _check_start_end(sliced_file, 50, 70);
+ eo_unref(sliced_file);
+ }
+
+ {
+ // cannot past end
+ Ecordova_File *sliced_file = eo_do_ret(file,
+ sliced_file,
+ ecordova_file_slice(150, 170));
+ _check_start_end(sliced_file, size, size);
+ eo_unref(sliced_file);
+ }
+
+ {
+ // negative values slices backwards
+ Ecordova_File *sliced_file = eo_do_ret(file,
+ sliced_file,
+ ecordova_file_slice(-70, -20));
+ _check_start_end(sliced_file, size - 70, size - 20);
+ eo_unref(sliced_file);
+ }
+
+ {
+ // negative values slices backwards (swapped)
+ Ecordova_File *sliced_file = eo_do_ret(file,
+ sliced_file,
+ ecordova_file_slice(-20, -70));
+ _check_start_end(sliced_file, size - 70, size - 20);
+ eo_unref(sliced_file);
+ }
+
+ eo_unref(file);
+}
+END_TEST
+
+START_TEST(name_get)
+{
+ const char *expected_filename = "filename.txt";
+ Ecordova_File *file = _file_new(expected_filename, "", "", 0, 0);
+
+ const char *actual_filename = eo_do_ret(file,
+ actual_filename,
+ ecordova_file_name_get());
+ ck_assert_str_eq(expected_filename, actual_filename);
+
+ eo_unref(file);
+}
+END_TEST
+
+START_TEST(url_get)
+{
+ const char *expected_url = "/tmp/filename.txt";
+ Ecordova_File *file = _file_new("filename.txt", expected_url, "", 0, 0);
+
+ const char *actual_url = eo_do_ret(file,
+ actual_url,
+ ecordova_file_url_get());
+ ck_assert_str_eq(expected_url, actual_url);
+
+ eo_unref(file);
+}
+END_TEST
+
+void
+ecordova_file_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, smoke);
+ tcase_add_test(tc, slice);
+ tcase_add_test(tc, name_get);
+ tcase_add_test(tc, url_get);
+}
diff --git a/src/tests/ecordova/ecordova_file_test.h b/src/tests/ecordova/ecordova_file_test.h
new file mode 100644
index 0000000000..766006404e
--- /dev/null
+++ b/src/tests/ecordova/ecordova_file_test.h
@@ -0,0 +1,9 @@
+#ifndef _ECORDOVA_FILE_TEST_H
+#define _ECORDOVA_FILE_TEST_H
+
+#include <Ecordova.h>
+#include <check.h>
+
+void ecordova_file_test(TCase *);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_fileentry_test.c b/src/tests/ecordova/ecordova_fileentry_test.c
new file mode 100644
index 0000000000..452c290cfe
--- /dev/null
+++ b/src/tests/ecordova/ecordova_fileentry_test.c
@@ -0,0 +1,211 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_fileentry_test.h"
+#include "ecordova_directoryentry_test.h"
+#include "ecordova_entry_test.h"
+#include "ecordova_suite.h"
+
+#include <Eio.h>
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Ecordova_File *
+_fileentry_new(const char *name,
+ const char *path,
+ Ecordova_FileSystem *file_system,
+ const char *url)
+{
+ return eo_add(ECORDOVA_FILEENTRY_CLASS,
+ NULL,
+ ecordova_fileentry_constructor(name,
+ path,
+ file_system,
+ url));
+}
+
+Ecordova_FileEntry *
+create_tmpfile(Eina_Tmpstr **url, unsigned char **content, size_t *size)
+{
+ *size = (rand() % 1024) + 1;
+ return create_tmpfile_size(url, content, *size);
+}
+
+Ecordova_FileEntry *
+create_tmpfile_size(Eina_Tmpstr **url, unsigned char **content, size_t size)
+{
+ int fd = eina_file_mkstemp("fileentry_test_XXXXXX.bin", url);
+ ck_assert_int_ne(-1, fd);
+ check_exists(*url);
+
+ const char *last_path_separator = strrchr(*url, '/');
+ fail_if(NULL == last_path_separator);
+
+ const char *name = last_path_separator + 1;
+ size_t len = last_path_separator - *url;
+ char path[len + 1];
+ strncpy(path, *url, len);
+ path[len] = '\0';
+
+ *content = generate_random_buffer_size(size);
+
+ write(fd, *content, size);
+ close(fd);
+
+ return _fileentry_new(name, path, NULL, *url);
+}
+
+unsigned char *
+generate_random_buffer(size_t *size)
+{
+ *size = (rand() % 1024) + 1;
+ return generate_random_buffer_size(*size);
+}
+
+unsigned char *
+generate_random_buffer_size(size_t size)
+{
+ unsigned char *content = malloc(size);
+ for (size_t i = 0; i < size; ++i)
+ content[i] = (unsigned char)(rand() % 256);
+ return content;
+}
+
+START_TEST(smoke)
+{
+ Ecordova_File *fileentry = _fileentry_new("", "", NULL, "");
+ eo_unref(fileentry);
+}
+END_TEST
+
+Eina_Bool
+_eo_get_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ Eo **object = data;
+ fail_if(NULL == event_info);
+
+ *object = eo_ref((Eo*)event_info);
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+static bool
+_fileentry_eo_get(Ecordova_Entry *file,
+ Eo **obj,
+ const Eo_Event_Description *desc,
+ void(*method)(void))
+{
+ *obj = NULL;
+ bool error = false;
+ bool timeout = false;
+
+ Ecore_Timer *timeout_timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+
+ eo_do(file, eo_event_callback_add(desc, _eo_get_cb, obj),
+ eo_event_callback_add(ECORDOVA_ENTRY_EVENT_ERROR, _error_cb, &error),
+ method());
+
+ ecore_main_loop_begin();
+
+ eo_do(file, eo_event_callback_del(desc, _eo_get_cb, obj),
+ eo_event_callback_del(ECORDOVA_ENTRY_EVENT_ERROR, _error_cb, &error));
+
+ eo_unref(timeout_timer);
+
+ fail_if(timeout);
+
+ return error;
+}
+
+static bool
+_fileentry_writer_create(Ecordova_FileEntry *file_entry,
+ Ecordova_FileWriter **filewriter)
+{
+ return _fileentry_eo_get(file_entry,
+ filewriter,
+ ECORDOVA_FILEENTRY_EVENT_CREATE_WRITER,
+ ecordova_fileentry_writer_create);
+}
+
+bool
+fileentry_file_get(Ecordova_FileEntry *file_entry,
+ Ecordova_File **file)
+{
+ return _fileentry_eo_get(file_entry,
+ file,
+ ECORDOVA_FILEENTRY_EVENT_FILE,
+ ecordova_fileentry_file);
+}
+
+START_TEST(writer_create)
+{
+ bool error = false;
+ Eina_Tmpstr *url = NULL;
+ unsigned char *content = NULL;
+ size_t size = 0;
+ Ecordova_FileEntry *file_entry = create_tmpfile(&url, &content, &size);
+
+ Ecordova_FileWriter *filewriter = NULL;
+ fail_if(error = _fileentry_writer_create(file_entry, &filewriter));
+ fail_if(NULL == filewriter);
+ eo_unref(filewriter);
+
+ fail_if(error = entry_remove(file_entry));
+ eo_unref(file_entry);
+ free(content);
+ eina_tmpstr_del(url);
+}
+END_TEST
+
+START_TEST(file_get)
+{
+ bool error = false;
+ Eina_Tmpstr *url = NULL;
+ unsigned char *content = NULL;
+ size_t size = 0;
+ Ecordova_FileEntry *file_entry = create_tmpfile(&url, &content, &size);
+
+ Ecordova_File *file = NULL;
+ fail_if(error = fileentry_file_get(file_entry, &file));
+ fail_if(NULL == file);
+
+ long actual_end = eo_do_ret(file, actual_end, ecordova_file_end_get());
+ long expected_end = size;
+ ck_assert_int_eq(expected_end, actual_end);
+
+ eo_unref(file);
+
+ fail_if(error = entry_remove(file_entry));
+ eo_unref(file_entry);
+ free(content);
+ eina_tmpstr_del(url);
+}
+END_TEST
+
+void
+ecordova_fileentry_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, smoke);
+ tcase_add_test(tc, writer_create);
+ tcase_add_test(tc, file_get);
+}
diff --git a/src/tests/ecordova/ecordova_fileentry_test.h b/src/tests/ecordova/ecordova_fileentry_test.h
new file mode 100644
index 0000000000..f1c4f04321
--- /dev/null
+++ b/src/tests/ecordova/ecordova_fileentry_test.h
@@ -0,0 +1,17 @@
+#ifndef _ECORDOVA_FILEENTRY_TEST_H
+#define _ECORDOVA_FILEENTRY_TEST_H
+
+#include <Ecordova.h>
+
+#include <check.h>
+
+#include <stdbool.h>
+
+void ecordova_fileentry_test(TCase *);
+Ecordova_FileEntry *create_tmpfile(Eina_Tmpstr **, unsigned char **, size_t *);
+Ecordova_FileEntry *create_tmpfile_size(Eina_Tmpstr **, unsigned char **, size_t);
+bool fileentry_file_get(Ecordova_FileEntry *, Ecordova_File **);
+unsigned char * generate_random_buffer(size_t*);
+unsigned char * generate_random_buffer_size(size_t);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_filereader_test.c b/src/tests/ecordova/ecordova_filereader_test.c
new file mode 100644
index 0000000000..d4ed04309e
--- /dev/null
+++ b/src/tests/ecordova/ecordova_filereader_test.c
@@ -0,0 +1,294 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_filereader_test.h"
+#include "ecordova_fileentry_test.h"
+#include "ecordova_directoryentry_test.h"
+#include "ecordova_entry_test.h"
+#include "ecordova_suite.h"
+
+#include <Eio.h>
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Ecordova_FileReader *
+_filereader_new(void)
+{
+ return eo_add(ECORDOVA_FILEREADER_CLASS,
+ NULL,
+ ecordova_filereader_constructor());
+}
+
+START_TEST(smoke)
+{
+ Ecordova_File *filereader = _filereader_new();
+ eo_unref(filereader);
+}
+END_TEST
+
+static Eina_Bool
+_main_loop_quit(void *data EINA_UNUSED,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+static Eina_Bool
+_bool_set(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ Ecordova_ProgressEvent *progress = event_info;
+ fail_if(NULL == progress);
+
+ bool *value = data;
+ *value = true;
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+bool
+filereader_read(Ecordova_File *file, char **content, size_t *length)
+{
+ *content = NULL;
+ *length = 0;
+ bool error = false;
+ bool timeout = false;
+
+ Ecordova_File *filereader = _filereader_new();
+ Ecore_Timer *timeout_timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+
+ eo_do(filereader, eo_event_callback_add(ECORDOVA_FILEREADER_EVENT_ON_LOAD_END, _main_loop_quit, NULL),
+ eo_event_callback_add(ECORDOVA_FILEREADER_EVENT_ON_ERROR, _bool_set, &error),
+ ecordova_filereader_read(file));
+
+ ecore_main_loop_begin();
+
+ eo_do(filereader, eo_event_callback_del(ECORDOVA_FILEREADER_EVENT_ON_LOAD_END, _main_loop_quit, NULL),
+ eo_event_callback_del(ECORDOVA_FILEREADER_EVENT_ON_ERROR, _bool_set, &error));
+
+ eo_unref(timeout_timer);
+
+ if (!error && !timeout)
+ {
+ *length = eo_do_ret(filereader, *length, ecordova_filereader_length_get());
+ if (*length)
+ {
+ const char *result = eo_do_ret(filereader, result, ecordova_filereader_result_get());
+ *content = malloc(*length);
+ memcpy(*content, result, *length);
+ }
+ }
+
+ eo_unref(filereader);
+
+ fail_if(timeout);
+
+ return error;
+}
+
+START_TEST(read_all)
+{
+ bool error = false;
+
+ Eina_Tmpstr *file_url = NULL;
+ unsigned char *expected_content = NULL;
+ size_t expected_size = 0;
+ Ecordova_FileEntry *file_entry = create_tmpfile(&file_url,
+ &expected_content,
+ &expected_size);
+
+ Ecordova_File *file = NULL;
+ fail_if(error = fileentry_file_get(file_entry, &file));
+
+ char *actual_content;
+ size_t actual_size;
+ fail_if(error = filereader_read(file, &actual_content, &actual_size));
+ ck_assert_int_eq(expected_size, actual_size);
+ ck_assert_int_eq(0, memcmp(expected_content, actual_content, expected_size));
+ free(actual_content);
+
+ eo_unref(file);
+
+ fail_if(error = entry_remove(file_entry));
+ eo_unref(file_entry);
+ free(expected_content);
+ eina_tmpstr_del(file_url);
+}
+END_TEST
+
+START_TEST(read_slice)
+{
+ bool error = false;
+
+ Eina_Tmpstr *file_url = NULL;
+ unsigned char *file_content = NULL;
+ size_t file_size = 1024;
+ Ecordova_FileEntry *file_entry = create_tmpfile_size(&file_url,
+ &file_content,
+ file_size);
+
+ Ecordova_File *file = NULL;
+ fail_if(error = fileentry_file_get(file_entry, &file));
+
+ // take the middle
+ size_t start = file_size / 3;
+ size_t end = file_size / 3 * 2;
+ Ecordova_File *sliced_file = eo_do_ret(file,
+ sliced_file,
+ ecordova_file_slice(start, end));
+ fail_if(NULL == sliced_file);
+
+ size_t expected_size = end - start;
+ unsigned char *expected_content = &file_content[start];
+
+ char *actual_content;
+ size_t actual_size;
+ fail_if(error = filereader_read(sliced_file, &actual_content, &actual_size));
+ ck_assert_int_eq(expected_size, actual_size);
+ ck_assert_int_eq(0, memcmp(expected_content, actual_content, expected_size));
+ free(actual_content);
+
+
+ eo_unref(sliced_file);
+ eo_unref(file);
+
+ fail_if(error = entry_remove(file_entry));
+ eo_unref(file_entry);
+ free(file_content);
+ eina_tmpstr_del(file_url);
+}
+END_TEST
+
+START_TEST(read_slice_page_size)
+{
+ bool error = false;
+
+ Eina_Tmpstr *file_url = NULL;
+ unsigned char *file_content = NULL;
+ const size_t file_size = eina_cpu_page_size() * 5;
+ Ecordova_FileEntry *file_entry = create_tmpfile_size(&file_url,
+ &file_content,
+ file_size);
+
+ Ecordova_File *file = NULL;
+ fail_if(error = fileentry_file_get(file_entry, &file));
+
+ // take the middle
+ size_t start = file_size / 3;
+ size_t end = file_size / 3 * 2;
+ Ecordova_File *sliced_file = eo_do_ret(file,
+ sliced_file,
+ ecordova_file_slice(start, end));
+ fail_if(NULL == sliced_file);
+
+ size_t expected_size = end - start;
+ unsigned char *expected_content = &file_content[start];
+
+ char *actual_content;
+ size_t actual_size;
+ fail_if(error = filereader_read(sliced_file, &actual_content, &actual_size));
+ ck_assert_int_eq(expected_size, actual_size);
+ ck_assert_int_eq(0, memcmp(expected_content, actual_content, expected_size));
+ free(actual_content);
+
+ eo_unref(sliced_file);
+ eo_unref(file);
+
+ fail_if(error = entry_remove(file_entry));
+ eo_unref(file_entry);
+ free(file_content);
+ eina_tmpstr_del(file_url);
+}
+END_TEST
+
+static Eina_Bool
+_filereader_abort(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ Ecordova_File *filereader = data;
+ fail_if(NULL == filereader);
+ eo_do(filereader, ecordova_filereader_abort());
+ return EO_CALLBACK_CONTINUE;
+}
+
+START_TEST(aborting)
+{
+ Eina_Tmpstr *file_url = NULL;
+ unsigned char *file_content = NULL;
+ size_t file_size = 0;
+ Ecordova_FileEntry *file_entry = create_tmpfile(&file_url,
+ &file_content,
+ &file_size);
+
+ bool error = false;
+ bool timeout = false;
+ bool aborted = false;
+
+ Ecordova_File *file = NULL;
+ fail_if(error = fileentry_file_get(file_entry, &file));
+
+ Ecordova_File *filereader = _filereader_new();
+ Ecore_Timer *timeout_timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+
+ eo_do(filereader, eo_event_callback_add(ECORDOVA_FILEREADER_EVENT_ON_LOAD_END, _main_loop_quit, NULL),
+ eo_event_callback_add(ECORDOVA_FILEREADER_EVENT_ON_PROGRESS, _filereader_abort, filereader),
+ eo_event_callback_add(ECORDOVA_FILEREADER_EVENT_ON_ABORT, _bool_set, &aborted),
+ eo_event_callback_add(ECORDOVA_FILEREADER_EVENT_ON_ERROR, _bool_set, &error),
+ ecordova_filereader_read(file));
+
+ ecore_main_loop_begin();
+
+ eo_do(filereader, eo_event_callback_del(ECORDOVA_FILEREADER_EVENT_ON_LOAD_END, _main_loop_quit, NULL),
+ eo_event_callback_del(ECORDOVA_FILEREADER_EVENT_ON_PROGRESS, _filereader_abort, filereader),
+ eo_event_callback_del(ECORDOVA_FILEREADER_EVENT_ON_ABORT, _bool_set, &aborted),
+ eo_event_callback_del(ECORDOVA_FILEREADER_EVENT_ON_ERROR, _bool_set, &error));
+
+ eo_unref(timeout_timer);
+ eo_unref(filereader);
+
+ fail_if(timeout);
+ fail_if(error);
+ fail_unless(aborted);
+
+ eo_unref(file);
+
+ fail_if(error = entry_remove(file_entry));
+ eo_unref(file_entry);
+ free(file_content);
+ eina_tmpstr_del(file_url);
+}
+END_TEST
+
+void
+ecordova_filereader_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, smoke);
+ tcase_add_test(tc, read_all);
+ tcase_add_test(tc, read_slice);
+ tcase_add_test(tc, read_slice_page_size);
+ tcase_add_test(tc, aborting);
+}
diff --git a/src/tests/ecordova/ecordova_filereader_test.h b/src/tests/ecordova/ecordova_filereader_test.h
new file mode 100644
index 0000000000..d7f59ce4fd
--- /dev/null
+++ b/src/tests/ecordova/ecordova_filereader_test.h
@@ -0,0 +1,13 @@
+#ifndef _ECORDOVA_FILEREADER_TEST_H
+#define _ECORDOVA_FILEREADER_TEST_H
+
+#include <Ecordova.h>
+
+#include <check.h>
+
+#include <stdbool.h>
+
+void ecordova_filereader_test(TCase *);
+bool filereader_read(Ecordova_File *file, char **content, size_t *length);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_filetransfer_test.c b/src/tests/ecordova/ecordova_filetransfer_test.c
new file mode 100644
index 0000000000..0aa435a388
--- /dev/null
+++ b/src/tests/ecordova/ecordova_filetransfer_test.c
@@ -0,0 +1,227 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_filetransfer_test.h"
+#include "ecordova_fileentry_test.h"
+#include "ecordova_directoryentry_test.h"
+#include "ecordova_entry_test.h"
+#include "ecordova_filereader_test.h"
+#include "ecordova_suite.h"
+
+#include <Ecore_Con.h>
+#include <Ecore_File.h>
+
+#include <stdbool.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+ ecore_con_init();
+}
+
+static void
+_teardown(void)
+{
+ ecore_con_shutdown();
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Ecordova_Device *
+_filetransfer_new(void)
+{
+ return eo_add(ECORDOVA_FILETRANSFER_CLASS,
+ NULL,
+ ecordova_filetransfer_constructor());
+}
+
+START_TEST(smoke)
+{
+ Ecordova_Device *filetransfer = _filetransfer_new();
+ eo_unref(filetransfer);
+}
+END_TEST
+
+static unsigned char *expected_content = NULL;
+static size_t expected_size = 0;
+
+static Eina_Bool
+_client_add_cb(void *data EINA_UNUSED,
+ int type EINA_UNUSED,
+ Ecore_Con_Event_Client_Add *event EINA_UNUSED)
+{
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_client_del_cb(void *data EINA_UNUSED,
+ int type EINA_UNUSED,
+ Ecore_Con_Event_Client_Del *event)
+{
+ ecore_con_client_del(event->client);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_client_data_cb(void *data EINA_UNUSED,
+ int type EINA_UNUSED,
+ Ecore_Con_Event_Client_Data *event)
+{
+ const char response_template[] =
+ "HTTP/1.1 200 OK\r\n"
+ "Server: filetransfer test httpserver\r\n"
+ "Content-Length: %s\r\n"
+ "Connection: close\r\n"
+ "Content-Type: application/octet-stream\r\n\r\n";
+
+ char content_length[15];
+ snprintf(content_length, sizeof(content_length), "%ld", expected_size);
+
+ size_t min_len = strlen(response_template) + strlen(content_length) + expected_size;
+ char *buffer = malloc(min_len);
+ snprintf(buffer, min_len, response_template, content_length);
+
+ size_t len = strlen(buffer);
+ memcpy(&buffer[len], expected_content, expected_size);
+ len += expected_size;
+
+ ecore_con_client_send(event->client, buffer, len);
+ ecore_con_client_flush(event->client);
+ free(buffer);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_server_del_cb(void *data EINA_UNUSED,
+ int type EINA_UNUSED,
+ Ecore_Con_Event_Server_Del *event EINA_UNUSED)
+{
+ ecore_main_loop_quit();
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_main_loop_quit_cb(void *data EINA_UNUSED,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+static Eina_Bool
+_set_bool(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ fail_if(NULL == data);
+ bool *value = data;
+ *value = true;
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+static Eina_Bool
+_on_progress_cb(void *data EINA_UNUSED,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ return EO_CALLBACK_CONTINUE;
+}
+
+START_TEST(download)
+{
+ const int server_port = 8181;
+ const char *server_address = "127.0.0.1";
+ Ecore_Con_Server *httpserver = ecore_con_server_add(ECORE_CON_REMOTE_TCP, server_address, server_port, NULL);
+ fail_if(NULL == httpserver);
+ ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD, (Ecore_Event_Handler_Cb)_client_add_cb, NULL);
+ ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, (Ecore_Event_Handler_Cb)_client_del_cb, NULL);
+ ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA, (Ecore_Event_Handler_Cb)_client_data_cb, NULL);
+ ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL, (Ecore_Event_Handler_Cb)_server_del_cb, NULL);
+
+ Eina_Tmpstr *file_url = NULL;
+ Ecordova_FileEntry *file_entry = create_tmpfile(&file_url, &expected_content, &expected_size);
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *tmpdir_entry = _create_tmpdir(&tmpdir);
+
+ const char *filename = ecore_file_file_get(file_url);
+ const char *protocol = "http://";
+ size_t len = strlen(protocol) + strlen(server_address) + 1 + 15 + 1 + strlen(filename) + 1;
+ char source[len];
+ snprintf(source, len, "%s%s:%d/%s", protocol, server_address, server_port, filename);
+
+ const char *download_extension = ".download";
+ len = strlen(file_url) + strlen(download_extension) + 1;
+ char target[len];
+ snprintf(target, len, "%s%s", file_url, download_extension);
+
+ Ecordova_Device *filetransfer = _filetransfer_new();
+
+ bool error = false;
+ bool timeout = false;
+
+ eo_do(filetransfer, eo_event_callback_add(ECORDOVA_FILETRANSFER_EVENT_DOWNLOAD_SUCCESS, _main_loop_quit_cb, NULL),
+ eo_event_callback_add(ECORDOVA_FILETRANSFER_EVENT_ON_PROGRESS, _on_progress_cb, NULL),
+ eo_event_callback_add(ECORDOVA_FILETRANSFER_EVENT_ERROR, _set_bool, &error),
+ ecordova_filetransfer_download(source, target, EINA_FALSE, NULL));
+
+ Ecore_Timer *timeout_timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+ ecore_main_loop_begin();
+ eo_unref(timeout_timer);
+
+ fail_if(error);
+ fail_if(timeout);
+
+ eo_unref(filetransfer);
+
+
+
+ Ecordova_FileEntry *downloaded_entry = NULL;
+ error = fileentry_get(tmpdir_entry, target, 0, &downloaded_entry);
+ fail_if(error);
+ fail_unless(NULL != downloaded_entry);
+ check_exists(file_url);
+
+
+ Ecordova_File *downloaded_file = NULL;
+ fail_if(error = fileentry_file_get(downloaded_entry, &downloaded_file));
+
+ char *actual_content;
+ size_t actual_size;
+ fail_if(error = filereader_read(downloaded_file, &actual_content, &actual_size));
+ ck_assert_int_eq(expected_size, actual_size);
+ ck_assert_int_eq(0, memcmp(expected_content, actual_content, expected_size));
+ free(actual_content);
+
+ eo_unref(downloaded_file);
+
+ fail_if(error = entry_remove(downloaded_entry));
+ eo_unref(downloaded_entry);
+ fail_if(error = entry_remove(file_entry));
+ eo_unref(file_entry);
+ fail_if(error = entry_remove(tmpdir_entry));
+ eo_unref(tmpdir_entry);
+ free(expected_content);
+ eina_tmpstr_del(file_url);
+ eina_tmpstr_del(tmpdir);
+
+ ecore_con_server_del(httpserver);
+ ecore_main_loop_begin();
+}
+END_TEST
+
+void
+ecordova_filetransfer_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, smoke);
+ tcase_add_test(tc, download);
+}
diff --git a/src/tests/ecordova/ecordova_filetransfer_test.h b/src/tests/ecordova/ecordova_filetransfer_test.h
new file mode 100644
index 0000000000..1aab4ddbe6
--- /dev/null
+++ b/src/tests/ecordova/ecordova_filetransfer_test.h
@@ -0,0 +1,9 @@
+#ifndef _ECORDOVA_FILETRANSFER_TEST_H
+#define _ECORDOVA_FILETRANSFER_TEST_H
+
+#include <Ecordova.h>
+#include <check.h>
+
+void ecordova_filetransfer_test(TCase *);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_filewriter_test.c b/src/tests/ecordova/ecordova_filewriter_test.c
new file mode 100644
index 0000000000..8fdc86f49a
--- /dev/null
+++ b/src/tests/ecordova/ecordova_filewriter_test.c
@@ -0,0 +1,218 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_filewriter_test.h"
+#include "ecordova_fileentry_test.h"
+#include "ecordova_directoryentry_test.h"
+#include "ecordova_entry_test.h"
+#include "ecordova_filereader_test.h"
+#include "ecordova_suite.h"
+
+#include <Eio.h>
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Ecordova_FileWriter *
+_filewriter_new(Ecordova_File *file)
+{
+ return eo_add(ECORDOVA_FILEWRITER_CLASS,
+ NULL,
+ ecordova_filewriter_constructor(file));
+}
+
+static Eina_Bool
+_main_loop_quit(void *data EINA_UNUSED,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+static Eina_Bool
+_bool_set(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ Ecordova_ProgressEvent *progress = event_info;
+ fail_if(NULL == progress);
+
+ bool *value = data;
+ *value = true;
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+static bool
+_filewriter_write(Ecordova_File *file, const char *content, size_t length)
+{
+ bool error = false;
+ bool timeout = false;
+
+ Ecordova_File *filewriter = _filewriter_new(file);
+ Ecore_Timer *timeout_timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+
+ eo_do(filewriter, eo_event_callback_add(ECORDOVA_FILEWRITER_EVENT_ON_WRITE_END, _main_loop_quit, NULL),
+ eo_event_callback_add(ECORDOVA_FILEWRITER_EVENT_ON_ERROR, _bool_set, &error),
+ ecordova_filewriter_write(content, length));
+
+ ecore_main_loop_begin();
+
+ eo_do(filewriter, eo_event_callback_del(ECORDOVA_FILEWRITER_EVENT_ON_WRITE_END, _main_loop_quit, NULL),
+ eo_event_callback_del(ECORDOVA_ENTRY_EVENT_ERROR, _bool_set, &error));
+
+ eo_unref(timeout_timer);
+
+ eo_unref(filewriter);
+
+ fail_if(timeout);
+
+ return error;
+}
+
+START_TEST(writer_all)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ const char *filename = "file.txt";
+ const char *filepath = tmpdir;
+ size_t len = strlen(filepath) + 1 + strlen(filename) + 1;
+ char file_url[len];
+ snprintf(file_url, len, "%s/%s", tmpdir, filename);
+
+ Ecordova_FileEntry *file_entry = NULL;
+ bool error = false;
+
+ // create exclusive
+ Ecordova_FileFlags flags = ECORDOVA_FILEFLAGS_CREATE | ECORDOVA_FILEFLAGS_EXCLUSIVE;
+ error = fileentry_get(directory_entry, filename, flags, &file_entry);
+ fail_if(error);
+ fail_unless(NULL != file_entry);
+ check_exists(file_url);
+
+ Ecordova_File *file = NULL;
+ fail_if(error = fileentry_file_get(file_entry, &file));
+ size_t expected_size;
+ unsigned char *expected_content = generate_random_buffer(&expected_size);
+ fail_if(error = _filewriter_write(file, (char*)expected_content, expected_size));
+ eo_unref(file);
+
+ fail_if(error = fileentry_file_get(file_entry, &file));
+ char *actual_content;
+ size_t actual_size;
+ fail_if(error = filereader_read(file, &actual_content, &actual_size));
+ ck_assert_int_eq(expected_size, actual_size);
+ ck_assert_int_eq(0, memcmp(expected_content, actual_content, expected_size));
+ free(actual_content);
+ eo_unref(file);
+
+ free(expected_content);
+
+ fail_if(error = entry_remove(file_entry));
+ eo_unref(file_entry);
+ fail_if(error = entry_remove(directory_entry));
+ eo_unref(directory_entry);
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+static Eina_Bool
+_filewriter_abort(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ Ecordova_File *filewriter = data;
+ fail_if(NULL == filewriter);
+ eo_do(filewriter, ecordova_filewriter_abort());
+ return EO_CALLBACK_CONTINUE;
+}
+
+START_TEST(aborting)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Ecordova_DirectoryEntry *directory_entry = _create_tmpdir(&tmpdir);
+
+ const char *filename = "file.txt";
+ const char *filepath = tmpdir;
+ size_t len = strlen(filepath) + 1 + strlen(filename) + 1;
+ char file_url[len];
+ snprintf(file_url, len, "%s/%s", tmpdir, filename);
+
+ Ecordova_FileEntry *file_entry = NULL;
+ bool error = false;
+ bool timeout = false;
+ bool aborted = false;
+
+ // create exclusive
+ Ecordova_FileFlags flags = ECORDOVA_FILEFLAGS_CREATE | ECORDOVA_FILEFLAGS_EXCLUSIVE;
+ error = fileentry_get(directory_entry, filename, flags, &file_entry);
+ fail_if(error);
+ fail_unless(NULL != file_entry);
+ check_exists(file_url);
+
+ Ecordova_File *file = NULL;
+ fail_if(error = fileentry_file_get(file_entry, &file));
+ size_t size;
+ unsigned char *content = generate_random_buffer(&size);
+
+ Ecordova_File *filewriter = _filewriter_new(file);
+ Ecore_Timer *timeout_timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+
+ eo_do(filewriter, eo_event_callback_add(ECORDOVA_FILEWRITER_EVENT_ON_WRITE_END, _main_loop_quit, NULL),
+ eo_event_callback_add(ECORDOVA_FILEWRITER_EVENT_ON_PROGRESS, _filewriter_abort, filewriter),
+ eo_event_callback_add(ECORDOVA_FILEWRITER_EVENT_ON_ABORT, _bool_set, &aborted),
+ eo_event_callback_add(ECORDOVA_FILEWRITER_EVENT_ON_ERROR, _bool_set, &error),
+ ecordova_filewriter_write((char*)content, size));
+
+ ecore_main_loop_begin();
+
+ eo_do(filewriter, eo_event_callback_del(ECORDOVA_FILEWRITER_EVENT_ON_WRITE_END, _main_loop_quit, NULL),
+ eo_event_callback_del(ECORDOVA_FILEWRITER_EVENT_ON_PROGRESS, _filewriter_abort, filewriter),
+ eo_event_callback_del(ECORDOVA_FILEWRITER_EVENT_ON_ABORT, _bool_set, &aborted),
+ eo_event_callback_del(ECORDOVA_FILEWRITER_EVENT_ON_ERROR, _bool_set, &error));
+
+ eo_unref(timeout_timer);
+ eo_unref(filewriter);
+
+ fail_if(timeout);
+ fail_if(error);
+ fail_unless(aborted);
+
+ eo_unref(file);
+ free(content);
+
+ fail_if(error = entry_remove(file_entry));
+ eo_unref(file_entry);
+ fail_if(error = entry_remove(directory_entry));
+ eo_unref(directory_entry);
+ eina_tmpstr_del(tmpdir);
+}
+END_TEST
+
+void
+ecordova_filewriter_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, writer_all);
+ tcase_add_test(tc, aborting);
+}
diff --git a/src/tests/ecordova/ecordova_filewriter_test.h b/src/tests/ecordova/ecordova_filewriter_test.h
new file mode 100644
index 0000000000..b7ac34ade2
--- /dev/null
+++ b/src/tests/ecordova/ecordova_filewriter_test.h
@@ -0,0 +1,9 @@
+#ifndef _ECORDOVA_FILEWRITER_TEST_H
+#define _ECORDOVA_FILEWRITER_TEST_H
+
+#include <Ecordova.h>
+#include <check.h>
+
+void ecordova_filewriter_test(TCase *);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_geolocation_test.c b/src/tests/ecordova/ecordova_geolocation_test.c
new file mode 100644
index 0000000000..04bc8f573f
--- /dev/null
+++ b/src/tests/ecordova/ecordova_geolocation_test.c
@@ -0,0 +1,93 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_geolocation_test.h"
+#include "ecordova_suite.h"
+
+#include <stdbool.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Ecordova_Device *
+_geolocation_new(void)
+{
+ return eo_add(ECORDOVA_GEOLOCATION_CLASS,
+ NULL,
+ ecordova_geolocation_constructor());
+}
+
+START_TEST(smoke)
+{
+ Ecordova_Device *geolocation = _geolocation_new();
+ eo_unref(geolocation);
+}
+END_TEST
+
+static Eina_Bool
+_current_position_get_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ bool *called = data;
+ *called = true;
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_error_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ bool *error = data;
+ *error = true;
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+START_TEST(current_position_get)
+{
+ Ecordova_Device *geolocation = _geolocation_new();
+
+ bool success_event_called = false;
+ bool error_event_called = false;
+ eo_do(geolocation, eo_event_callback_add(ECORDOVA_GEOLOCATION_EVENT_CURRENT_SUCCESS, _current_position_get_cb, &success_event_called));
+ eo_do(geolocation, eo_event_callback_add(ECORDOVA_GEOLOCATION_EVENT_ERROR, _error_cb, &error_event_called));
+ const Ecordova_Geolocation_Options options = {
+ .enable_high_accuracy = false,
+ .timeout = 4000
+ };
+ eo_do(geolocation, ecordova_geolocation_current_position_get(&options));
+
+ if (!success_event_called && !error_event_called)
+ ecore_main_loop_begin();
+
+ fail_if(error_event_called);
+ fail_unless(success_event_called);
+
+ eo_unref(geolocation);
+}
+END_TEST
+
+void
+ecordova_geolocation_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, smoke);
+ //tcase_add_test(tc, current_position_get); // disabled: not supported
+}
diff --git a/src/tests/ecordova/ecordova_geolocation_test.h b/src/tests/ecordova/ecordova_geolocation_test.h
new file mode 100644
index 0000000000..a65c34df59
--- /dev/null
+++ b/src/tests/ecordova/ecordova_geolocation_test.h
@@ -0,0 +1,9 @@
+#ifndef _ECORDOVA_GEOLOCATION_TEST_H
+#define _ECORDOVA_GEOLOCATION_TEST_H
+
+#include <Ecordova.h>
+#include <check.h>
+
+void ecordova_geolocation_test(TCase *);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_globalization_test.c b/src/tests/ecordova/ecordova_globalization_test.c
new file mode 100644
index 0000000000..d55ab728a5
--- /dev/null
+++ b/src/tests/ecordova/ecordova_globalization_test.c
@@ -0,0 +1,594 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_globalization_test.h"
+#include "ecordova_suite.h"
+
+#include <stdbool.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Ecordova_Device *
+_globalization_new(void)
+{
+ return eo_add(ECORDOVA_GLOBALIZATION_CLASS,
+ NULL,
+ ecordova_globalization_constructor());
+}
+
+START_TEST(smoke)
+{
+ Ecordova_Device *globalization = _globalization_new();
+ eo_unref(globalization);
+}
+END_TEST
+
+static Eina_Bool
+_preferred_language_get_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ fail_if(NULL == data);
+ char **language = data;
+ fail_if(NULL == event_info);
+ Ecordova_Globalization_Language *glanguage = event_info;
+
+ *language = strdup(glanguage->value);
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+START_TEST(preferred_language_get)
+{
+ Ecordova_Device *globalization = _globalization_new();
+
+ char *language = NULL;
+ eo_do(globalization,
+ eo_event_callback_add(ECORDOVA_GLOBALIZATION_EVENT_PREFERRED_LANGUAGE_SUCCESS,
+ _preferred_language_get_cb,
+ &language));
+ eo_do(globalization, ecordova_globalization_preferred_language_get());
+ fail_if(NULL == language);
+
+ DBG("language: %s", language);
+ free(language);
+
+ eo_unref(globalization);
+}
+END_TEST
+
+static Eina_Bool
+_locale_name_get_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ fail_if(NULL == data);
+ char **locale = data;
+ fail_if(NULL == event_info);
+ Ecordova_Globalization_Locale *glocale = event_info;
+
+ *locale = strdup(glocale->value);
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+START_TEST(locale_name_get)
+{
+ Ecordova_Device *globalization = _globalization_new();
+
+ char *locale = NULL;
+ eo_do(globalization,
+ eo_event_callback_add(ECORDOVA_GLOBALIZATION_EVENT_LOCALE_NAME_SUCCESS,
+ _locale_name_get_cb,
+ &locale));
+ eo_do(globalization, ecordova_globalization_locale_name_get());
+ fail_if(NULL == locale);
+
+ DBG("locale: %s", locale);
+ free(locale);
+
+ eo_unref(globalization);
+}
+END_TEST
+
+static Eina_Bool
+_to_string_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ fail_if(NULL == data);
+ char **string = data;
+ fail_if(NULL == event_info);
+ Ecordova_Globalization_String *gstring = event_info;
+
+ *string = strdup(gstring->value);
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+START_TEST(date_to_string)
+{
+ Ecordova_Device *globalization = _globalization_new();
+
+ time_t date_time;
+ time(&date_time);
+
+ char *string = NULL;
+ eo_do(globalization,
+ eo_event_callback_add(ECORDOVA_GLOBALIZATION_EVENT_DATE_TO_STRING_SUCCESS,
+ _to_string_cb,
+ &string));
+ eo_do(globalization, ecordova_globalization_date_to_string(date_time, NULL));
+ fail_if(NULL == string);
+
+ DBG("string: %s", string);
+ free(string);
+
+ eo_unref(globalization);
+}
+END_TEST
+
+typedef struct {
+ bool success;
+ Ecordova_Globalization_CurrencyPattern pattern;
+} CurrencyPatternData;
+
+static Eina_Bool
+_currency_pattern_get_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ fail_if(NULL == data);
+ CurrencyPatternData *currency_pattern_data = data;
+ fail_if(NULL == event_info);
+ Ecordova_Globalization_CurrencyPattern *currency_pattern = event_info;
+
+ currency_pattern_data->success = true;
+ currency_pattern_data->pattern = (Ecordova_Globalization_CurrencyPattern){
+ .pattern = currency_pattern->pattern ? strdup(currency_pattern->pattern) : NULL,
+ .code = currency_pattern->code ? strdup(currency_pattern->code) : NULL,
+ .fraction = currency_pattern->fraction,
+ .rounding = currency_pattern->rounding,
+ .decimal = currency_pattern->decimal ? strdup(currency_pattern->decimal) : NULL,
+ .grouping = currency_pattern->grouping ? strdup(currency_pattern->grouping) : NULL
+ };
+
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+START_TEST(currency_pattern_get)
+{
+ Ecordova_Device *globalization = _globalization_new();
+
+ CurrencyPatternData currency_pattern_data = {0};
+ eo_do(globalization,
+ eo_event_callback_add(ECORDOVA_GLOBALIZATION_EVENT_CURRENCY_PATTERN_SUCCESS,
+ _currency_pattern_get_cb,
+ &currency_pattern_data));
+ eo_do(globalization, ecordova_globalization_currency_pattern_get(NULL));
+ fail_unless(currency_pattern_data.success);
+
+ DBG("pattern: %s", currency_pattern_data.pattern.pattern);
+ DBG("code: %s", currency_pattern_data.pattern.code);
+ DBG("fraction: %d", currency_pattern_data.pattern.fraction);
+ DBG("rounding: %f", currency_pattern_data.pattern.rounding);
+ DBG("decimal: %s", currency_pattern_data.pattern.decimal);
+ DBG("grouping: %s", currency_pattern_data.pattern.grouping);
+ free((char*)currency_pattern_data.pattern.pattern);
+ free((char*)currency_pattern_data.pattern.code);
+ free((char*)currency_pattern_data.pattern.decimal);
+ free((char*)currency_pattern_data.pattern.grouping);
+
+ eo_unref(globalization);
+}
+END_TEST
+
+typedef struct {
+ bool success;
+ Ecordova_Globalization_DateNames names;
+} DateNamesData;
+
+static Eina_Bool
+_date_names_get_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ fail_if(NULL == data);
+ DateNamesData *date_names_data = data;
+ fail_if(NULL == event_info);
+ Ecordova_Globalization_DateNames *date_names = event_info;
+ fail_if(NULL == date_names->value);
+ date_names_data->success = true;
+
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+START_TEST(date_names_get)
+{
+ Ecordova_Device *globalization = _globalization_new();
+
+ DateNamesData date_names_data = {0};
+ eo_do(globalization,
+ eo_event_callback_add(ECORDOVA_GLOBALIZATION_EVENT_DATE_NAMES_SUCCESS,
+ _date_names_get_cb,
+ &date_names_data));
+ eo_do(globalization, ecordova_globalization_date_names_get(NULL));
+ fail_unless(date_names_data.success);
+
+ eo_unref(globalization);
+}
+END_TEST
+
+typedef struct {
+ bool success;
+ Ecordova_Globalization_DatePattern pattern;
+} DatePatternData;
+
+static Eina_Bool
+_date_pattern_get_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ fail_if(NULL == data);
+ DatePatternData *date_pattern_data = data;
+ fail_if(NULL == event_info);
+ Ecordova_Globalization_DatePattern *date_pattern = event_info;
+
+ date_pattern_data->success = true;
+ date_pattern_data->pattern = (Ecordova_Globalization_DatePattern){
+ .pattern = date_pattern->pattern ? strdup(date_pattern->pattern) : NULL,
+ .timezone = date_pattern->timezone ? strdup(date_pattern->timezone) : NULL,
+ .utc_offset = date_pattern->utc_offset,
+ .dst_offset = date_pattern->dst_offset,
+ };
+
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+START_TEST(date_pattern_get)
+{
+ Ecordova_Device *globalization = _globalization_new();
+
+ DatePatternData date_pattern_data = {0};
+ eo_do(globalization,
+ eo_event_callback_add(ECORDOVA_GLOBALIZATION_EVENT_DATE_PATTERN_SUCCESS,
+ _date_pattern_get_cb,
+ &date_pattern_data));
+ eo_do(globalization, ecordova_globalization_date_pattern_get(NULL));
+ fail_unless(date_pattern_data.success);
+
+ DBG("pattern: %s", date_pattern_data.pattern.pattern);
+ DBG("timezone: %s", date_pattern_data.pattern.timezone);
+ DBG("utc_offset: %d", date_pattern_data.pattern.utc_offset);
+ DBG("dst_offset: %d", date_pattern_data.pattern.dst_offset);
+ free((char*)date_pattern_data.pattern.pattern);
+ free((char*)date_pattern_data.pattern.timezone);
+
+ eo_unref(globalization);
+}
+END_TEST
+
+typedef struct {
+ bool success;
+ Ecordova_Globalization_FirstDayOfWeek first_day_of_week;
+} FirstDayOfWeekData;
+
+static Eina_Bool
+_first_day_of_week_get_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ fail_if(NULL == data);
+ FirstDayOfWeekData *first_day_of_week_data = data;
+ fail_if(NULL == event_info);
+ Ecordova_Globalization_FirstDayOfWeek *first_day_of_week = event_info;
+
+ first_day_of_week_data->success = true;
+ first_day_of_week_data->first_day_of_week = (Ecordova_Globalization_FirstDayOfWeek){
+ .value = first_day_of_week->value,
+ };
+
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+START_TEST(first_day_of_week_get)
+{
+ Ecordova_Device *globalization = _globalization_new();
+
+ FirstDayOfWeekData first_day_of_week_data = {0};
+ eo_do(globalization,
+ eo_event_callback_add(ECORDOVA_GLOBALIZATION_EVENT_DATE_PATTERN_SUCCESS,
+ _first_day_of_week_get_cb,
+ &first_day_of_week_data));
+ eo_do(globalization, ecordova_globalization_date_pattern_get(NULL));
+ fail_unless(first_day_of_week_data.success);
+
+ DBG("first_day_of_week: %d", first_day_of_week_data.first_day_of_week.value);
+
+ eo_unref(globalization);
+}
+END_TEST
+
+typedef struct {
+ bool success;
+ Ecordova_Globalization_NumberPattern pattern;
+} NumberPatternData;
+
+static Eina_Bool
+_number_pattern_get_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ fail_if(NULL == data);
+ NumberPatternData *number_pattern_data = data;
+ fail_if(NULL == event_info);
+ Ecordova_Globalization_NumberPattern *number_pattern = event_info;
+
+ number_pattern_data->success = true;
+ number_pattern_data->pattern = (Ecordova_Globalization_NumberPattern){
+ .pattern = number_pattern->pattern ? strdup(number_pattern->pattern) : NULL,
+ .symbol = number_pattern->symbol ? strdup(number_pattern->symbol) : NULL,
+ .fraction = number_pattern->fraction,
+ .rounding = number_pattern->rounding,
+ .positive = number_pattern->positive ? strdup(number_pattern->positive) : NULL,
+ .negative = number_pattern->negative ? strdup(number_pattern->negative) : NULL,
+ .decimal = number_pattern->decimal ? strdup(number_pattern->decimal) : NULL,
+ .grouping = number_pattern->grouping ? strdup(number_pattern->grouping) : NULL
+ };
+
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+START_TEST(number_pattern_get)
+{
+ Ecordova_Device *globalization = _globalization_new();
+
+ NumberPatternData number_pattern_data = {0};
+ eo_do(globalization,
+ eo_event_callback_add(ECORDOVA_GLOBALIZATION_EVENT_NUMBER_PATTERN_SUCCESS,
+ _number_pattern_get_cb,
+ &number_pattern_data));
+ eo_do(globalization, ecordova_globalization_number_pattern_get(NULL));
+ fail_unless(number_pattern_data.success);
+
+ DBG("pattern: %s", number_pattern_data.pattern.pattern);
+ DBG("symbol: %s", number_pattern_data.pattern.symbol);
+ DBG("fraction: %d", number_pattern_data.pattern.fraction);
+ DBG("rounding: %f", number_pattern_data.pattern.rounding);
+ DBG("positive: %s", number_pattern_data.pattern.positive);
+ DBG("negative: %s", number_pattern_data.pattern.negative);
+ DBG("decimal: %s", number_pattern_data.pattern.decimal);
+ DBG("grouping: %s", number_pattern_data.pattern.grouping);
+ free((char*)number_pattern_data.pattern.pattern);
+ free((char*)number_pattern_data.pattern.symbol);
+ free((char*)number_pattern_data.pattern.positive);
+ free((char*)number_pattern_data.pattern.negative);
+ free((char*)number_pattern_data.pattern.decimal);
+ free((char*)number_pattern_data.pattern.grouping);
+
+ eo_unref(globalization);
+}
+END_TEST
+
+
+typedef struct {
+ bool success;
+ Ecordova_Globalization_DayLightSavingsTime is_day_light_savings_time;
+} DayLightSavingsTimeIsData;
+
+static Eina_Bool
+_is_day_light_savings_time_get_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ fail_if(NULL == data);
+ DayLightSavingsTimeIsData *is_day_light_savings_time_data = data;
+ fail_if(NULL == event_info);
+ Ecordova_Globalization_DayLightSavingsTime *is_day_light_savings_time = event_info;
+
+ is_day_light_savings_time_data->success = true;
+ is_day_light_savings_time_data->is_day_light_savings_time = (Ecordova_Globalization_DayLightSavingsTime){
+ .dst = is_day_light_savings_time->dst,
+ };
+
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+START_TEST(is_day_light_savings_time)
+{
+ Ecordova_Device *globalization = _globalization_new();
+
+ time_t date_time;
+ time(&date_time);
+
+ DayLightSavingsTimeIsData is_day_light_savings_time_data = {0};
+ eo_do(globalization,
+ eo_event_callback_add(ECORDOVA_GLOBALIZATION_EVENT_DAY_LIGHT_SAVINGS_TIME_SUCCESS,
+ _is_day_light_savings_time_get_cb,
+ &is_day_light_savings_time_data));
+ eo_do(globalization, ecordova_globalization_day_light_savings_time_is(date_time));
+ fail_unless(is_day_light_savings_time_data.success);
+
+ DBG("is_day_light_savings_time: %d", is_day_light_savings_time_data.is_day_light_savings_time.dst);
+
+ eo_unref(globalization);
+}
+END_TEST
+
+START_TEST(number_to_string)
+{
+ Ecordova_Device *globalization = _globalization_new();
+
+ double number = 12345.6789;
+
+ char *string = NULL;
+ eo_do(globalization,
+ eo_event_callback_add(ECORDOVA_GLOBALIZATION_EVENT_NUMBER_TO_STRING_SUCCESS,
+ _to_string_cb,
+ &string));
+ eo_do(globalization, ecordova_globalization_number_to_string(number, NULL));
+ fail_if(NULL == string);
+
+ DBG("string: %s", string);
+ free(string);
+
+ eo_unref(globalization);
+}
+END_TEST
+
+typedef struct {
+ bool success;
+ Ecordova_Globalization_DateTime date_time;
+} StringToDateData;
+
+static Eina_Bool
+_string_to_date_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ fail_if(NULL == data);
+ StringToDateData *date_time_data = data;
+ fail_if(NULL == event_info);
+ Ecordova_Globalization_DateTime *date_time = event_info;
+
+ date_time_data->success = true;
+ date_time_data->date_time = (Ecordova_Globalization_DateTime){
+ .year = date_time->year,
+ .month = date_time->month,
+ .day = date_time->day,
+ .hour = date_time->hour,
+ .minute = date_time->minute,
+ .second = date_time->second,
+ .millisecond = date_time->millisecond
+ };
+
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+START_TEST(string_to_date)
+{
+ Ecordova_Device *globalization = _globalization_new();
+
+ time_t date_time;
+ time(&date_time);
+
+ char *dateString = NULL;
+ eo_do(globalization,
+ eo_event_callback_add(ECORDOVA_GLOBALIZATION_EVENT_DATE_TO_STRING_SUCCESS,
+ _to_string_cb,
+ &dateString));
+ eo_do(globalization, ecordova_globalization_date_to_string(date_time, NULL));
+ fail_if(NULL == dateString);
+
+ StringToDateData string_to_date_data = {0};
+ eo_do(globalization,
+ eo_event_callback_add(ECORDOVA_GLOBALIZATION_EVENT_STRING_TO_DATE_SUCCESS,
+ _string_to_date_cb,
+ &string_to_date_data));
+ eo_do(globalization, ecordova_globalization_string_to_date(dateString, NULL));
+ fail_unless(string_to_date_data.success);
+
+ DBG("year: %d", string_to_date_data.date_time.year);
+ DBG("month: %d", string_to_date_data.date_time.month);
+ DBG("day: %d", string_to_date_data.date_time.day);
+ DBG("hour: %d", string_to_date_data.date_time.hour);
+ DBG("minute: %d", string_to_date_data.date_time.minute);
+ DBG("second: %d", string_to_date_data.date_time.second);
+ DBG("millisecond: %d", string_to_date_data.date_time.millisecond);
+
+ free(dateString);
+ eo_unref(globalization);
+}
+END_TEST
+
+typedef struct {
+ bool success;
+ Ecordova_Globalization_Number number;
+} StringToNumberData;
+
+static Eina_Bool
+_string_to_number_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ fail_if(NULL == data);
+ StringToNumberData *string_to_number_data = data;
+ fail_if(NULL == event_info);
+ Ecordova_Globalization_Number *number = event_info;
+
+ string_to_number_data->success = true;
+ string_to_number_data->number = (Ecordova_Globalization_Number){
+ .value = number->value,
+ };
+
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+START_TEST(string_to_number)
+{
+ Ecordova_Device *globalization = _globalization_new();
+
+ StringToNumberData string_to_number_data = {0};
+ eo_do(globalization,
+ eo_event_callback_add(ECORDOVA_GLOBALIZATION_EVENT_STRING_TO_NUMBER_SUCCESS,
+ _string_to_number_cb,
+ &string_to_number_data));
+ eo_do(globalization, ecordova_globalization_string_to_number("12345.6789", NULL));
+ fail_unless(string_to_number_data.success);
+
+ DBG("number: %f", string_to_number_data.number.value);
+
+ eo_unref(globalization);
+}
+END_TEST
+
+void
+ecordova_globalization_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, smoke);
+ tcase_add_test(tc, preferred_language_get);
+ tcase_add_test(tc, locale_name_get);
+ tcase_add_test(tc, date_to_string);
+ tcase_add_test(tc, currency_pattern_get);
+ tcase_add_test(tc, date_names_get);
+ tcase_add_test(tc, date_pattern_get);
+ tcase_add_test(tc, first_day_of_week_get);
+ tcase_add_test(tc, number_pattern_get);
+ tcase_add_test(tc, is_day_light_savings_time);
+ tcase_add_test(tc, number_to_string);
+ tcase_add_test(tc, string_to_date);
+ tcase_add_test(tc, string_to_number);
+}
diff --git a/src/tests/ecordova/ecordova_globalization_test.h b/src/tests/ecordova/ecordova_globalization_test.h
new file mode 100644
index 0000000000..a64102b838
--- /dev/null
+++ b/src/tests/ecordova/ecordova_globalization_test.h
@@ -0,0 +1,9 @@
+#ifndef _ECORDOVA_GLOBALIZATION_TEST_H
+#define _ECORDOVA_GLOBALIZATION_TEST_H
+
+#include <Ecordova.h>
+#include <check.h>
+
+void ecordova_globalization_test(TCase *);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_media_test.c b/src/tests/ecordova/ecordova_media_test.c
new file mode 100644
index 0000000000..c8d79ca314
--- /dev/null
+++ b/src/tests/ecordova/ecordova_media_test.c
@@ -0,0 +1,44 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_media_test.h"
+#include "ecordova_suite.h"
+
+#include <stdbool.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Ecordova_Device *
+_media_new(void)
+{
+ return eo_add(ECORDOVA_MEDIA_CLASS,
+ NULL,
+ ecordova_media_constructor(""));
+}
+
+START_TEST(smoke)
+{
+ Ecordova_Device *media = _media_new();
+ eo_unref(media);
+}
+END_TEST
+
+void
+ecordova_media_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ //tcase_add_test(tc, smoke); // disabled: not supported on common profile
+}
diff --git a/src/tests/ecordova/ecordova_media_test.h b/src/tests/ecordova/ecordova_media_test.h
new file mode 100644
index 0000000000..f26291efb1
--- /dev/null
+++ b/src/tests/ecordova/ecordova_media_test.h
@@ -0,0 +1,9 @@
+#ifndef _ECORDOVA_MEDIA_TEST_H
+#define _ECORDOVA_MEDIA_TEST_H
+
+#include <Ecordova.h>
+#include <check.h>
+
+void ecordova_media_test(TCase *);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_mediafile_test.c b/src/tests/ecordova/ecordova_mediafile_test.c
new file mode 100644
index 0000000000..e58e954ccd
--- /dev/null
+++ b/src/tests/ecordova/ecordova_mediafile_test.c
@@ -0,0 +1,142 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_mediafile_test.h"
+#include "ecordova_directoryentry_test.h"
+#include "ecordova_suite.h"
+
+#include <Eio.h>
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Ecordova_MediaFile *
+_mediafile_new(const char *name,
+ const char *url,
+ const char *type,
+ time_t last_modified_date,
+ long size)
+{
+ return eo_add(ECORDOVA_MEDIAFILE_CLASS,
+ NULL,
+ ecordova_mediafile_constructor(name,
+ url,
+ type,
+ last_modified_date,
+ size));
+}
+
+START_TEST(smoke)
+{
+ Ecordova_Media *mediafile = _mediafile_new("test.txt", "/", "text/plain", 0, 0);
+ eo_unref(mediafile);
+}
+END_TEST
+
+static Eina_Bool
+_main_loop_quit(void *data EINA_UNUSED,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ fail_if(NULL == data);
+ Ecordova_MediaFileData *mediafile_data = data;
+ fail_if(NULL == event_info);
+ *mediafile_data = *(Ecordova_MediaFileData*)event_info;
+
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+static Eina_Bool
+_bool_set(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info)
+{
+ Ecordova_ProgressEvent *progress = event_info;
+ fail_if(NULL == progress);
+
+ bool *value = data;
+ *value = true;
+ ecore_main_loop_quit();
+ return EO_CALLBACK_CONTINUE;
+}
+
+static bool
+_format_data_get(Ecordova_MediaFile *file, Ecordova_MediaFileData *data)
+{
+ *data = (Ecordova_MediaFileData){0};
+ bool error = false;
+ bool timeout = false;
+
+ Ecore_Timer *timeout_timer = eo_add(ECORE_TIMER_CLASS, NULL, ecore_obj_timer_constructor(10, _timeout_cb, &timeout));
+
+ eo_do(file, eo_event_callback_add(ECORDOVA_MEDIAFILE_EVENT_SUCCESS, _main_loop_quit, data),
+ eo_event_callback_add(ECORDOVA_MEDIAFILE_EVENT_ERROR, _bool_set, &error),
+ ecordova_mediafile_format_data_get());
+
+ ecore_main_loop_begin();
+
+ eo_do(file, eo_event_callback_del(ECORDOVA_MEDIAFILE_EVENT_SUCCESS, _main_loop_quit, data),
+ eo_event_callback_del(ECORDOVA_MEDIAFILE_EVENT_ERROR, _bool_set, &error));
+
+ eo_unref(timeout_timer);
+ fail_if(timeout);
+
+ return error;
+}
+
+
+START_TEST(formatdata_get)
+{
+ const char *media_sample_filename = "44khz32kbps.mp3";
+ size_t len = strlen(TESTS_SRC_DIR) + 1 + strlen(media_sample_filename) + 1;
+ char media_sample_url[len];
+ snprintf(media_sample_url, len, "%s/%s", TESTS_SRC_DIR, media_sample_filename);
+
+ Eina_File *media_sample_file = eina_file_open(media_sample_url, EINA_FALSE);
+ size_t media_sample_file_size = eina_file_size_get(media_sample_file);
+ time_t media_sample_modified_date = eina_file_mtime_get(media_sample_file);
+ eina_file_close(media_sample_file);
+
+ Ecordova_Media *mediafile = _mediafile_new(media_sample_filename,
+ media_sample_url,
+ "audio/mpeg3",
+ media_sample_modified_date,
+ media_sample_file_size);
+
+ bool error = false;
+ Ecordova_MediaFileData mediafile_data;
+ fail_if(error = _format_data_get(mediafile, &mediafile_data));
+ fail_unless(NULL == mediafile_data.codecs);
+ ck_assert_int_eq(32000, mediafile_data.bitrate);
+ ck_assert_int_eq(0, mediafile_data.height);
+ ck_assert_int_eq(0, mediafile_data.width);
+ ck_assert_int_eq(55, mediafile_data.duration);
+ eo_unref(mediafile);
+}
+END_TEST
+
+void
+ecordova_mediafile_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, smoke);
+ tcase_add_test(tc, formatdata_get);
+}
diff --git a/src/tests/ecordova/ecordova_mediafile_test.h b/src/tests/ecordova/ecordova_mediafile_test.h
new file mode 100644
index 0000000000..ace9eac0dc
--- /dev/null
+++ b/src/tests/ecordova/ecordova_mediafile_test.h
@@ -0,0 +1,12 @@
+#ifndef _ECORDOVA_MEDIAFILE_TEST_H
+#define _ECORDOVA_MEDIAFILE_TEST_H
+
+#include <Ecordova.h>
+
+#include <check.h>
+
+#include <stdbool.h>
+
+void ecordova_mediafile_test(TCase *);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_networkinformation_test.c b/src/tests/ecordova/ecordova_networkinformation_test.c
new file mode 100644
index 0000000000..a3b98b53dc
--- /dev/null
+++ b/src/tests/ecordova/ecordova_networkinformation_test.c
@@ -0,0 +1,44 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_networkinformation_test.h"
+#include "ecordova_suite.h"
+
+#include <stdbool.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Ecordova_Device *
+_networkinformation_new(void)
+{
+ return eo_add(ECORDOVA_NETWORKINFORMATION_CLASS,
+ NULL,
+ ecordova_networkinformation_constructor());
+}
+
+START_TEST(smoke)
+{
+ Ecordova_Device *networkinformation = _networkinformation_new();
+ eo_unref(networkinformation);
+}
+END_TEST
+
+void
+ecordova_networkinformation_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ //tcase_add_test(tc, smoke); // disabled: not supported on common profile
+}
diff --git a/src/tests/ecordova/ecordova_networkinformation_test.h b/src/tests/ecordova/ecordova_networkinformation_test.h
new file mode 100644
index 0000000000..dadce8818c
--- /dev/null
+++ b/src/tests/ecordova/ecordova_networkinformation_test.h
@@ -0,0 +1,9 @@
+#ifndef _ECORDOVA_NETWORKINFORMATION_TEST_H
+#define _ECORDOVA_NETWORKINFORMATION_TEST_H
+
+#include <Ecordova.h>
+#include <check.h>
+
+void ecordova_networkinformation_test(TCase *);
+
+#endif
diff --git a/src/tests/ecordova/ecordova_suite.c b/src/tests/ecordova/ecordova_suite.c
new file mode 100644
index 0000000000..032e3616c1
--- /dev/null
+++ b/src/tests/ecordova/ecordova_suite.c
@@ -0,0 +1,163 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_contacts_test.h"
+#include "ecordova_device_test.h"
+#include "ecordova_devicemotion_test.h"
+#include "ecordova_deviceorientation_test.h"
+#include "ecordova_geolocation_test.h"
+#include "ecordova_batterystatus_test.h"
+#include "ecordova_console_test.h"
+#include "ecordova_filetransfer_test.h"
+#include "ecordova_media_test.h"
+#include "ecordova_networkinformation_test.h"
+#include "ecordova_vibration_test.h"
+#include "ecordova_directoryreader_test.h"
+#include "ecordova_directoryentry_test.h"
+#include "ecordova_entry_test.h"
+#include "ecordova_file_test.h"
+#include "ecordova_fileentry_test.h"
+#include "ecordova_filereader_test.h"
+#include "ecordova_filewriter_test.h"
+#include "ecordova_mediafile_test.h"
+#include "ecordova_globalization_test.h"
+
+#include <Eina.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "ecordova_suite.h"
+
+int _test_ecordova_log_dom = -1;
+
+typedef struct _Ecordova_Test_Case Ecordova_Test_Case;
+
+struct _Ecordova_Test_Case
+{
+ const char *test_case;
+ void (*build)(TCase *tc);
+};
+
+static const Ecordova_Test_Case etc[] = {
+ //{ "contacts", ecordova_contacts_test },
+ { "device", ecordova_device_test },
+ { "devicemotion", ecordova_devicemotion_test },
+ { "deviceorientation", ecordova_deviceorientation_test },
+ { "geolocation", ecordova_geolocation_test },
+ { "batterystatus", ecordova_batterystatus_test },
+ { "console", ecordova_console_test },
+ { "filetransfer", ecordova_filetransfer_test },
+ { "media", ecordova_media_test },
+ { "networkinformation", ecordova_networkinformation_test },
+ { "vibration", ecordova_vibration_test },
+ { "directoryreader", ecordova_directoryreader_test },
+ { "directoryentry", ecordova_directoryentry_test },
+ { "entry", ecordova_entry_test },
+ { "file", ecordova_file_test },
+ { "fileentry", ecordova_fileentry_test },
+ { "filereader", ecordova_filereader_test },
+ { "filewriter", ecordova_filewriter_test },
+ { "mediafile", ecordova_mediafile_test },
+ { "globalization", ecordova_globalization_test },
+ { NULL, NULL }
+};
+
+static void
+_list_tests(void)
+{
+ const Ecordova_Test_Case *it = etc;
+ fputs("Available Test Cases:\n", stderr);
+ for (; it->test_case; it++)
+ fprintf(stderr, "\t%s\n", it->test_case);
+}
+
+static bool
+_use_test(int argc, const char **argv, const char *test_case)
+{
+ if (argc < 1)
+ return true;
+
+ for (; argc > 0; argc--, argv++)
+ if (strcmp(test_case, *argv) == 0)
+ return true;
+ return false;
+}
+
+static Suite *
+_ecordova_suite_build(int argc, const char **argv)
+{
+ Suite *s = suite_create("Ecordova");
+
+ for (int i = 0; etc[i].test_case; ++i)
+ {
+ if (!_use_test(argc, argv, etc[i].test_case)) continue;
+ TCase *tc = tcase_create(etc[i].test_case);
+
+ etc[i].build(tc);
+
+ suite_add_tcase(s, tc);
+ //tcase_set_timeout(tc, 0);
+ }
+
+ return s;
+}
+
+static void
+_init_logging(void)
+{
+ if (!eina_init())
+ ck_abort_msg("Ecordova: Unable to initialize eina");
+
+ _test_ecordova_log_dom = eina_log_domain_register("test_ecordova", EINA_COLOR_LIGHTBLUE);
+ if (_test_ecordova_log_dom < 0)
+ ck_abort_msg("Could not register log domain: test_ecordova");
+}
+
+static void
+_shutdown_logging(void)
+{
+ eina_log_domain_unregister(_test_ecordova_log_dom);
+ _test_ecordova_log_dom = -1;
+}
+
+int
+main(int argc, char **argv)
+{
+ for (int i = 1; i < argc; ++i)
+ {
+ if ((strcmp(argv[i], "-h") == 0) ||
+ (strcmp(argv[i], "--help") == 0))
+ {
+ fprintf(stderr, "Usage:\n\t%s [test_case1 .. [test_caseN]]\n", argv[0]);
+ _list_tests();
+ return 0;
+ }
+ else if ((strcmp(argv[i], "-l") == 0) ||
+ (strcmp(argv[i], "--list") == 0))
+ {
+ _list_tests();
+ return 0;
+ }
+ }
+
+ srand(time(NULL));
+
+ _init_logging();
+
+ Suite *s = _ecordova_suite_build(argc - 1, (const char **)argv + 1);
+ SRunner *sr = srunner_create(s);
+
+ srunner_set_xml(sr, TESTS_BUILD_DIR "/check-results.xml");
+
+ srunner_run_all(sr, CK_ENV);
+ int failed_count = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ _shutdown_logging();
+
+ return (failed_count == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/tests/ecordova/ecordova_suite.h b/src/tests/ecordova/ecordova_suite.h
new file mode 100644
index 0000000000..8f4ad28912
--- /dev/null
+++ b/src/tests/ecordova/ecordova_suite.h
@@ -0,0 +1,14 @@
+#ifndef _SOAP_SUITE_H
+#define _SOAP_SUITE_H
+
+#include <check.h>
+
+extern int _test_ecordova_log_dom;
+
+#define CRI(...) EINA_LOG_DOM_CRIT(_test_ecordova_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_test_ecordova_log_dom, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(_test_ecordova_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_test_ecordova_log_dom, __VA_ARGS__)
+#define DBG(...) EINA_LOG_DOM_DBG(_test_ecordova_log_dom, __VA_ARGS__)
+
+#endif
diff --git a/src/tests/ecordova/ecordova_vibration_test.c b/src/tests/ecordova/ecordova_vibration_test.c
new file mode 100644
index 0000000000..aaf228da4d
--- /dev/null
+++ b/src/tests/ecordova/ecordova_vibration_test.c
@@ -0,0 +1,44 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecordova_vibration_test.h"
+#include "ecordova_suite.h"
+
+#include <stdbool.h>
+
+static void
+_setup(void)
+{
+ int ret = ecordova_init();
+ ck_assert_int_eq(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = ecordova_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Ecordova_Device *
+_vibration_new(void)
+{
+ return eo_add(ECORDOVA_VIBRATION_CLASS,
+ NULL,
+ ecordova_vibration_constructor());
+}
+
+START_TEST(smoke)
+{
+ Ecordova_Device *vibration = _vibration_new();
+ eo_unref(vibration);
+}
+END_TEST
+
+void
+ecordova_vibration_test(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ //tcase_add_test(tc, smoke); // disabled: not supported on common profile
+}
diff --git a/src/tests/ecordova/ecordova_vibration_test.h b/src/tests/ecordova/ecordova_vibration_test.h
new file mode 100644
index 0000000000..84792a3a7e
--- /dev/null
+++ b/src/tests/ecordova/ecordova_vibration_test.h
@@ -0,0 +1,9 @@
+#ifndef _ECORDOVA_VIBRATION_TEST_H
+#define _ECORDOVA_VIBRATION_TEST_H
+
+#include <Ecordova.h>
+#include <check.h>
+
+void ecordova_vibration_test(TCase *);
+
+#endif
diff --git a/src/tests/evas/evas_test_textblock.c b/src/tests/evas/evas_test_textblock.c
index d15465c9fb..9499230837 100644
--- a/src/tests/evas/evas_test_textblock.c
+++ b/src/tests/evas/evas_test_textblock.c
@@ -16,6 +16,14 @@
#include "evas_tests_helpers.h"
+#if !defined(ck_assert_int_le)
+# define ck_assert_int_le(X, Y) _ck_assert_int(X, <=, Y)
+#endif
+
+#if !defined(ck_assert_int_gt)
+# define ck_assert_int_gt(X, Y) _ck_assert_int(X, >, Y)
+#endif
+
/* Functions defined in evas_object_textblock.c */
EAPI Eina_Bool
_evas_textblock_check_item_node_link(Evas_Object *obj);