Integrate changes from Tizen 2.4 48/42448/1
authorMu-Woong <muwoong.lee@samsung.com>
Mon, 29 Jun 2015 08:46:35 +0000 (17:46 +0900)
committerMu-Woong <muwoong.lee@samsung.com>
Mon, 29 Jun 2015 08:46:35 +0000 (17:46 +0900)
- Modify media log table creation sequence
- Add media playback event monitor using media-content API
- Add active window monitor for app usage logging

Change-Id: I145040e4175698b1d5b5d396c20967293876789b
Signed-off-by: Mu-Woong <muwoong.lee@samsung.com>
14 files changed:
CMakeLists.txt
packaging/statistics-context-provider.spec
src/app/app_stats_provider.cpp
src/app/app_use_monitor/active_window_monitor.cpp [new file with mode: 0644]
src/app/app_use_monitor/active_window_monitor.h [new file with mode: 0644]
src/app/app_use_monitor/launch_monitor.cpp [moved from src/app/launch_monitor.cpp with 82% similarity]
src/app/app_use_monitor/launch_monitor.h [moved from src/app/launch_monitor.h with 82% similarity]
src/media/db_handle.cpp
src/media/db_handle.h
src/media/media_content_monitor.cpp [new file with mode: 0644]
src/media/media_content_monitor.h [new file with mode: 0644]
src/media/media_stats_provider.cpp
src/media/media_stats_types.h
src/media_dummy/media_stats_provider.cpp [new file with mode: 0644]

index 2af2f93..18bfe7b 100644 (file)
@@ -8,7 +8,6 @@ SET(target_provider "ctx-stats-provider")
 # Source Lists
 FILE(GLOB SRCS src/shared/*.cpp)
 FILE(GLOB SRCS ${SRCS} src/app/*.cpp)
-FILE(GLOB SRCS ${SRCS} src/media/*.cpp)
 
 # Dependencies
 SET(provider_deps "context-common capi-system-runtime-info pkgmgr pkgmgr-info capi-appfw-package-manager")
@@ -20,9 +19,11 @@ MESSAGE("PROFILE: ${PROFILE}")
 # Dependencies regarding profiles
 IF("${PROFILE}" STREQUAL "mobile")
        ADD_DEFINITIONS("-D_MOBILE_")
+       FILE(GLOB SRCS ${SRCS} src/media/*.cpp)
        FILE(GLOB SRCS ${SRCS} src/social/*.cpp)
-       SET(provider_deps "${provider_deps} contacts-service2")
+       SET(provider_deps "${provider_deps} contacts-service2 capi-content-media-content")
 ELSE("${PROFILE}" STREQUAL "mobile")
+       FILE(GLOB SRCS ${SRCS} src/media_dummy/*.cpp)
        FILE(GLOB SRCS ${SRCS} src/social_dummy/*.cpp)
 ENDIF("${PROFILE}" STREQUAL "mobile")
 
@@ -33,6 +34,14 @@ ELSE("${ARCH}" STREQUAL "arm")
        ADD_DEFINITIONS("-D_EMULATOR_")
 ENDIF("${ARCH}" STREQUAL "arm")
 
+IF("${ACTIVE_WINDOW_HOOK}" STREQUAL "on")
+       ADD_DEFINITIONS("-D_USE_ACTIVE_WINDOW_HOOKING_")
+       SET(provider_deps "${provider_deps} ecore ecore-x")
+       SET(SRCS ${SRCS} src/app/app_use_monitor/active_window_monitor.cpp)
+ELSE("${ACTIVE_WINDOW_HOOK}" STREQUAL "on")
+       SET(SRCS ${SRCS} src/app/app_use_monitor/launch_monitor.cpp)
+ENDIF("${ACTIVE_WINDOW_HOOK}" STREQUAL "on")
+
 # Common Options
 INCLUDE(FindPkgConfig)
 INCLUDE_DIRECTORIES(
index 82f0f24..083b58a 100644 (file)
@@ -1,11 +1,14 @@
 Name:       statistics-context-provider
 Summary:    Statistics Context Provider
-Version:    0.4.2
+Version:    0.4.3
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0
 Source0:    %{name}-%{version}.tar.gz
 
+# Using the active window hooking for app monitoring, via ecore-x
+%define ACTIVE_WINDOW_HOOK on
+
 BuildRequires: cmake
 BuildRequires: pkgconfig(context-common)
 
@@ -20,6 +23,12 @@ BuildRequires: pkgconfig(capi-network-wifi)
 
 %if "%{?tizen_profile_name}" == "mobile"
 BuildRequires: pkgconfig(contacts-service2)
+BuildRequires: pkgconfig(capi-content-media-content)
+%endif
+
+%if "%{ACTIVE_WINDOW_HOOK}" == "on"
+BuildRequires: pkgconfig(ecore)
+BuildRequires: pkgconfig(ecore-x)
 %endif
 
 %ifarch %{arm}
@@ -51,7 +60,8 @@ export   CFLAGS+=" -DTIZEN_ENGINEER_MODE"
 export CXXFLAGS+=" -DTIZEN_ENGINEER_MODE"
 export   FFLAGS+=" -DTIZEN_ENGINEER_MODE"
 
-cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DARCH=%{ARCH} -DMAJORVER=${MAJORVER} -DFULLVER=%{version} -DPROFILE=%{?tizen_profile_name} -DBINTYPE=%{BINTYPE}
+cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DARCH=%{ARCH} -DMAJORVER=${MAJORVER} -DFULLVER=%{version} -DPROFILE=%{?tizen_profile_name} \
+                                                          -DBINTYPE=%{BINTYPE} -DACTIVE_WINDOW_HOOK=%{ACTIVE_WINDOW_HOOK}
 make %{?jobs:-j%jobs}
 
 %install
index 00a53cb..162b73a 100644 (file)
 
 #include "db_init.h"
 #include "install_monitor.h"
-#include "launch_monitor.h"
+
+#ifdef _USE_ACTIVE_WINDOW_HOOKING_
+#include "app_use_monitor/active_window_monitor.h"
+#else
+#include "app_use_monitor/launch_monitor.h"
+#endif
 
 static ctx::app_install_monitor *install_mon = NULL;
-static ctx::app_launch_monitor *launch_mon = NULL;
+static ctx::app_use_monitor *launch_mon = NULL;
 
 EXTAPI ctx::app_statistics_provider::app_statistics_provider()
 {
@@ -47,7 +52,7 @@ bool ctx::app_statistics_provider::init()
        IF_FAIL_RETURN_TAG(initializer, false, _E, "Memory allocation failed");
 
        install_mon = new(std::nothrow) ctx::app_install_monitor();
-       launch_mon = new(std::nothrow) ctx::app_launch_monitor();
+       launch_mon = new(std::nothrow) ctx::app_use_monitor();
        IF_FAIL_CATCH_TAG(install_mon && launch_mon, _E, "Memory allocation failed");
 
        context_manager::register_provider(APP_SUBJ_FREQUENTLY_USED, this);
diff --git a/src/app/app_use_monitor/active_window_monitor.cpp b/src/app/app_use_monitor/active_window_monitor.cpp
new file mode 100644 (file)
index 0000000..da04c1a
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+#include <time.h>
+#include <sstream>
+#include <Ecore_X.h>
+#include <app_manager.h>
+
+#include <db_mgr.h>
+#include <json.h>
+#include <types_internal.h>
+#include <system_info.h>
+#include "../app_stats_types.h"
+#include "active_window_monitor.h"
+
+/* Active window changes frequently.
+ * We thus consider the apps being foregrounded at least 3 secs */
+#define MIN_VALID_USE_TIME 2
+
+static Ecore_Event_Handler *window_property_event_handler;
+
+ctx::app_use_monitor::app_use_monitor()
+       : last_timestamp(0)
+       , last_pid(-1)
+{
+       start_logging();
+}
+
+ctx::app_use_monitor::~app_use_monitor()
+{
+       stop_logging();
+}
+
+bool ctx::app_use_monitor::start_logging()
+{
+       /* This ecore_x based approach does not work with virtualization features */
+       if(window_property_event_handler == NULL) {
+               ecore_x_init(NULL);
+               ecore_x_event_mask_set(ecore_x_window_root_first_get(), ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
+               window_property_event_handler = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY, on_window_property_changed, this);
+               IF_FAIL_RETURN_TAG(window_property_event_handler, false, _E, "ecore_event_handler_add() failed");
+               _D("Active window monitoring started");
+       }
+
+       return true;
+}
+
+void ctx::app_use_monitor::stop_logging()
+{
+       if (window_property_event_handler) {
+               ecore_event_handler_del(window_property_event_handler);
+               window_property_event_handler = NULL;
+               _D("Active window monitoring stopped");
+       }
+}
+
+Eina_Bool ctx::app_use_monitor::on_window_property_changed(void* data, int type, void* event)
+{
+       IF_FAIL_RETURN_TAG(data && event, ECORE_CALLBACK_PASS_ON, _W, "Invalid window event");
+
+       Ecore_X_Event_Window_Property *property = static_cast<Ecore_X_Event_Window_Property*>(event);
+       Ecore_X_Atom atom = ecore_x_atom_get("_NET_ACTIVE_WINDOW");
+
+       IF_FAIL_RETURN(property->atom == atom, ECORE_CALLBACK_PASS_ON);
+
+       int pid = 0;
+       Ecore_X_Window win = 0;
+
+       ecore_x_window_prop_window_get(property->win, atom, &win, 1);
+       ecore_x_netwm_pid_get(win, &pid);
+
+       IF_FAIL_RETURN_TAG(pid > 0, ECORE_CALLBACK_PASS_ON, _W, "Invalid pid");
+
+       app_use_monitor *instance = static_cast<app_use_monitor*>(data);
+       instance->on_active_window_changed(pid);
+
+       return ECORE_CALLBACK_PASS_ON;
+}
+
+void ctx::app_use_monitor::on_active_window_changed(int pid)
+{
+       IF_FAIL_VOID(last_pid != pid);
+       _D("Active window changed: PID-%d", pid);
+
+       int timestamp = static_cast<int>(time(NULL));
+       int duration = timestamp - last_timestamp;
+
+       if (!last_app_id.empty() > 0 && duration >= MIN_VALID_USE_TIME)
+               verify_used_app(last_app_id.c_str(), duration);
+
+       last_timestamp = timestamp;
+       last_pid = pid;
+
+       char *app_id = NULL;
+       app_manager_get_app_id(pid, &app_id);
+       last_app_id = (app_id ? app_id : "");
+       g_free(app_id);
+       _D("Current Active App: %s", last_app_id.c_str());
+}
+
+void ctx::app_use_monitor::verify_used_app(const char *app_id, int duration)
+{
+       app_info_h app_info = NULL;
+       int err = app_manager_get_app_info(app_id, &app_info);
+       IF_FAIL_VOID_TAG(err == APP_MANAGER_ERROR_NONE && app_info, _E, "app_manager_get_app_info() failed");
+
+       bool nodisp = false;
+       err = app_info_is_nodisplay(app_info, &nodisp);
+       IF_FAIL_CATCH_TAG(err == APP_MANAGER_ERROR_NONE, _E, "app_info_is_nodisplay() failed");
+       IF_FAIL_CATCH(!nodisp);
+
+       insert_log(app_id, duration);
+
+CATCH:
+       if (app_info)
+               app_info_destroy(app_info);
+}
+
+void ctx::app_use_monitor::insert_log(const char *app_id, int duration)
+{
+       int audiojack;
+       int system_volume;
+       int media_volume;
+       std::string bssid;
+
+       std::stringstream cols;
+       std::stringstream vals;
+
+       /* App ID */
+       cols << STATS_APP_ID << ",";
+       vals << "'" << app_id << "',";
+
+       /* Audio Jack */
+       if (ctx::system_info::get_audio_jack_state(&audiojack)) {
+               cols << STATS_AUDIO_JACK << ",";
+               vals << audiojack << ",";
+       }
+
+       /* Volume */
+       if (ctx::system_info::get_volume(&system_volume, &media_volume)) {
+               cols << STATS_SYSTEM_VOLUME << "," << STATS_MEDIA_VOLUME << ",";
+               vals << system_volume << "," << media_volume << ",";
+       }
+
+       /* BSSID */
+       if (ctx::system_info::get_wifi_bssid(bssid)) {
+               cols << STATS_BSSID << ",";
+               vals << "'" << bssid << "',";
+       }
+
+       /* Time */
+       cols << STATS_UNIV_TIME << ",";
+       vals << "(strftime('%s', 'now')) - " << duration << ",";
+
+       cols << STATS_LOCAL_TIME << ",";
+       vals << "(strftime('%s', 'now', 'localtime')) - " << duration << ",";
+
+       /* Duration */
+       cols << STATS_DURATION;
+       vals << duration;
+
+       std::stringstream query;
+       query << "INSERT INTO " << APP_TABLE_USAGE_LOG << " ("
+               << cols.str() << ") VALUES (" << vals.str() << ")";
+
+       db_manager::execute(0, query.str().c_str(), NULL);
+}
diff --git a/src/app/app_use_monitor/active_window_monitor.h b/src/app/app_use_monitor/active_window_monitor.h
new file mode 100644 (file)
index 0000000..e853c7c
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONTEXT_APP_USE_MONITOR_H__
+#define __CONTEXT_APP_USE_MONITOR_H__
+
+#include <string>
+#include <Ecore.h>
+
+namespace ctx {
+
+       class app_use_monitor {
+       private:
+               int last_timestamp;
+               int last_pid;
+               std::string last_app_id;
+
+               bool start_logging(void);
+               void stop_logging(void);
+
+               void verify_used_app(const char *app_id, int duration);
+               void insert_log(const char *app_id, int duration);
+
+               void on_active_window_changed(int pid);
+               static Eina_Bool on_window_property_changed(void* data, int type, void* event);
+
+       public:
+               app_use_monitor();
+               ~app_use_monitor();
+       };      /* class app_use_monitor */
+
+}      /* namespace ctx */
+
+#endif /* __CONTEXT_APP_USE_MONITOR_H__ */
similarity index 82%
rename from src/app/launch_monitor.cpp
rename to src/app/app_use_monitor/launch_monitor.cpp
index cd29dce..ce32987 100644 (file)
 #include <zone_util.h>
 
 #include <system_info.h>
-#include "app_stats_types.h"
+#include "../app_stats_types.h"
 #include "launch_monitor.h"
 
-ctx::app_launch_monitor::app_launch_monitor()
+ctx::app_use_monitor::app_use_monitor()
 {
        start_logging();
 }
 
-ctx::app_launch_monitor::~app_launch_monitor()
+ctx::app_use_monitor::~app_use_monitor()
 {
        stop_logging();
 }
 
-bool ctx::app_launch_monitor::start_logging()
+bool ctx::app_use_monitor::start_logging()
 {
        scope_zone_joiner sz(zone_util::default_zone());
 
@@ -43,14 +43,14 @@ bool ctx::app_launch_monitor::start_logging()
        return true;
 }
 
-void ctx::app_launch_monitor::stop_logging()
+void ctx::app_use_monitor::stop_logging()
 {
        scope_zone_joiner sz(zone_util::default_zone());
 
        app_manager_unset_app_context_event_cb();
 }
 
-void ctx::app_launch_monitor::app_context_event_cb(app_context_h app_context, app_context_event_e event, void *user_data)
+void ctx::app_use_monitor::app_context_event_cb(app_context_h app_context, app_context_event_e event, void *user_data)
 {
        scope_zone_joiner sz(zone_util::default_zone());
 
@@ -58,7 +58,7 @@ void ctx::app_launch_monitor::app_context_event_cb(app_context_h app_context, ap
        int err = app_context_get_app_id(app_context, &app_id);
        IF_FAIL_VOID_TAG(err == APP_MANAGER_ERROR_NONE, _E, "app_context_get_app_id() failed");
 
-       app_launch_monitor *monitor = static_cast<app_launch_monitor*>(user_data);
+       app_use_monitor *monitor = static_cast<app_use_monitor*>(user_data);
 
        if (event == APP_CONTEXT_EVENT_LAUNCHED) {
                monitor->log_launch_event(app_id);
@@ -68,7 +68,7 @@ void ctx::app_launch_monitor::app_context_event_cb(app_context_h app_context, ap
        g_free(app_id);
 }
 
-void ctx::app_launch_monitor::log_launch_event(const char* app_id)
+void ctx::app_use_monitor::log_launch_event(const char* app_id)
 {
        int audiojack;
        int system_volume;
@@ -91,7 +91,7 @@ void ctx::app_launch_monitor::log_launch_event(const char* app_id)
        db_manager::insert(0, APP_TABLE_USAGE_LOG, data, NULL);
 }
 
-void ctx::app_launch_monitor::log_terminate_event(const char* app_id)
+void ctx::app_use_monitor::log_terminate_event(const char* app_id)
 {
        std::stringstream query;
        query <<
similarity index 82%
rename from src/app/launch_monitor.h
rename to src/app/app_use_monitor/launch_monitor.h
index 3d63ada..43b3f66 100644 (file)
  * limitations under the License.
  */
 
-#ifndef __CONTEXT_APP_LAUNCH_MONITOR_H__
-#define __CONTEXT_APP_LAUNCH_MONITOR_H__
+#ifndef __CONTEXT_APP_USE_MONITOR_H__
+#define __CONTEXT_APP_USE_MONITOR_H__
 
 #include <app_manager.h>
 #include <db_listener_iface.h>
 
 namespace ctx {
 
-       class app_launch_monitor : public db_listener_iface {
+       class app_use_monitor : public db_listener_iface {
        private:
                bool start_logging(void);
                void stop_logging(void);
@@ -37,10 +37,10 @@ namespace ctx {
                static void app_context_event_cb(app_context_h app_context, app_context_event_e event, void *user_data);
 
        public:
-               app_launch_monitor();
-               ~app_launch_monitor();
-       };      /* class app_launch_monitor */
+               app_use_monitor();
+               ~app_use_monitor();
+       };      /* class app_use_monitor */
 
 }      /* namespace ctx */
 
-#endif /* __CONTEXT_APP_LAUNCH_MONITOR_H__ */
+#endif /* __CONTEXT_APP_USE_MONITOR_H__ */
index 8a86a05..430aad0 100644 (file)
 ctx::media_db_handle::media_db_handle(const char* zone)
        : stats_db_handle_base(zone)
 {
-       create_table();
 }
 
 ctx::media_db_handle::~media_db_handle()
 {
 }
 
-void ctx::media_db_handle::create_table()
-{
-       static bool done = false;
-       IF_FAIL_VOID(!done);
-
-       db_manager::create_table(generate_qid(), MEDIA_TABLE_NAME, MEDIA_TABLE_COLUMNS, NULL, NULL);
-
-       done = true;
-}
-
 int ctx::media_db_handle::read(const char* subject, ctx::json filter)
 {
        //TODO: filter validation (in the API side?)
@@ -74,45 +63,11 @@ int ctx::media_db_handle::read(const char* subject, ctx::json filter)
        return ERR_NONE;
 }
 
-int ctx::media_db_handle::write(const char* subject, ctx::json data)
-{
-       std::string app_id;
-       int media_type = -1;
-       int action_type = -1;
-
-       data.get(NULL, COMMON_ATTR_CLIENT_APP_ID, &app_id);
-       IF_FAIL_RETURN_TAG(!app_id.empty(), ERR_OPERATION_FAILED, _E, "No AppId");
-
-       if (STR_EQ(subject, MEDIA_SUBJ_START_MUSIC)) {
-               media_type = MEDIA_TYPE_MUSIC;
-               action_type = MEDIA_ACTION_START;
-
-       } else if (STR_EQ(subject, MEDIA_SUBJ_STOP_MUSIC)) {
-               media_type = MEDIA_TYPE_MUSIC;
-               action_type = MEDIA_ACTION_STOP;
-
-       } else if (STR_EQ(subject, MEDIA_SUBJ_START_VIDEO)) {
-               media_type = MEDIA_TYPE_VIDEO;
-               action_type = MEDIA_ACTION_START;
-
-       } else if (STR_EQ(subject, MEDIA_SUBJ_STOP_VIDEO)) {
-               media_type = MEDIA_TYPE_VIDEO;
-               action_type = MEDIA_ACTION_STOP;
-
-       } else {
-               return ERR_NOT_SUPPORTED;
-       }
-
-       IF_FAIL_RETURN(insert_log(app_id, media_type, action_type), ERR_OPERATION_FAILED);
-       return ERR_NONE;
-}
-
 std::string ctx::media_db_handle::create_where_clause(int media_type, ctx::json filter)
 {
        std::stringstream where_clause;
 
-       where_clause << MEDIA_TYPE " = " << media_type << " AND ";
-       where_clause << MEDIA_ACTION " = " << MEDIA_ACTION_START << " AND ";
+       where_clause << CX_MEDIA_TYPE " = " << media_type << " AND ";
        where_clause << stats_db_handle_base::create_where_clause(filter);
 
        return where_clause.str();
@@ -152,23 +107,3 @@ std::string ctx::media_db_handle::create_sql_frequency(int media_type, ctx::json
 
        return query.str();
 }
-
-bool ctx::media_db_handle::insert_log(std::string app_id, int media_type, int action_type)
-{
-       int system_volume = -1, media_volume = -1, audiojack = -1;
-
-       json data;
-       data.set(NULL, STATS_APP_ID, app_id);
-       data.set(NULL, MEDIA_TYPE, media_type);
-       data.set(NULL, MEDIA_ACTION, action_type);
-
-       if (ctx::system_info::get_audio_jack_state(&audiojack))
-               data.set(NULL, STATS_AUDIO_JACK, audiojack);
-
-       if (ctx::system_info::get_volume(&system_volume, &media_volume)) {
-               data.set(NULL, STATS_SYSTEM_VOLUME, system_volume);
-               data.set(NULL, STATS_MEDIA_VOLUME, media_volume);
-       }
-
-       return db_manager::insert(generate_qid(), MEDIA_TABLE_NAME, data, this);
-}
index a793427..fa1555f 100644 (file)
@@ -28,12 +28,8 @@ namespace ctx {
                        ~media_db_handle();
 
                        int read(const char* subject, ctx::json filter);
-                       int write(const char* subject, ctx::json data);
 
                private:
-                       void create_table();;
-                       bool insert_log(std::string app_id, int media_type, int action_type);
-
                        std::string create_where_clause(int media_type, ctx::json filter);
                        std::string create_sql_peak_time(int media_type, ctx::json filter);
                        std::string create_sql_common_setting(int media_type, ctx::json filter);
diff --git a/src/media/media_content_monitor.cpp b/src/media/media_content_monitor.cpp
new file mode 100644 (file)
index 0000000..e92c290
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+#include <types_internal.h>
+#include <db_mgr.h>
+#include <system_info.h>
+#include "media_stats_types.h"
+#include "db_handle.h"
+#include "media_content_monitor.h"
+
+ctx::media_content_monitor::media_content_monitor()
+       : started(false)
+{
+       db_manager::create_table(0, MEDIA_TABLE_NAME, MEDIA_TABLE_COLUMNS, NULL, NULL);
+       db_manager::execute(0, MEDIA_PLAYCOUNT_TABLE_SCHEMA, NULL);
+
+       started = start_monitoring();
+}
+
+ctx::media_content_monitor::~media_content_monitor()
+{
+       if (started)
+               stop_monitoring();
+}
+
+bool ctx::media_content_monitor::start_monitoring()
+{
+       int err;
+       err = media_content_connect();
+       IF_FAIL_RETURN_TAG(err == MEDIA_CONTENT_ERROR_NONE, false, _E, "media_content_connect() failed");
+
+       err = media_content_set_db_updated_cb(on_media_content_db_updated, this);
+       if (err != MEDIA_CONTENT_ERROR_NONE) {
+               media_content_disconnect();
+               _E("media_content_set_db_updated_cb() failed");
+               return false;
+       }
+
+       return true;
+}
+
+void ctx::media_content_monitor::stop_monitoring()
+{
+       media_content_unset_db_updated_cb();
+       media_content_disconnect();
+}
+
+void ctx::media_content_monitor::on_media_content_db_updated(
+               media_content_error_e error, int pid,
+               media_content_db_update_item_type_e update_item,
+               media_content_db_update_type_e update_type,
+               media_content_type_e media_type,
+               char *uuid, char *path, char *mime_type, void *user_data)
+{
+       IF_FAIL_VOID(error == MEDIA_CONTENT_ERROR_NONE && uuid != NULL);
+       IF_FAIL_VOID(update_item == MEDIA_ITEM_FILE && update_type == MEDIA_CONTENT_UPDATE);
+       IF_FAIL_VOID(media_type == MEDIA_CONTENT_TYPE_MUSIC || media_type == MEDIA_CONTENT_TYPE_VIDEO);
+
+       media_info_h media = NULL;
+       media_info_get_media_from_db(uuid, &media);
+       IF_FAIL_VOID_TAG(media, _E, "media_info_get_media_from_db() failed");
+
+       int cnt = -1;
+       media_info_get_played_count(media, &cnt);
+       media_info_destroy(media);
+       IF_FAIL_VOID_TAG(cnt >= 0, _E, "Invalid play count");
+
+       media_content_monitor *instance = static_cast<media_content_monitor*>(user_data);
+       instance->update_play_count(uuid,
+                       (media_type == MEDIA_CONTENT_TYPE_MUSIC) ? MEDIA_TYPE_MUSIC : MEDIA_TYPE_VIDEO,
+                       cnt);
+}
+
+void ctx::media_content_monitor::update_play_count(const char *uuid, int type, int count)
+{
+       std::stringstream query;
+       query << "INSERT OR IGNORE INTO Log_MediaPlayCount" \
+               " (UUID, MediaType) VALUES ('" << uuid << "'," << type <<");" \
+               "UPDATE Log_MediaPlayCount SET Diff = " << count << " - Count," \
+               " Count = " << count << " WHERE UUID = '" << uuid << "';" \
+               "SELECT MediaType FROM Log_MediaPlayCount" \
+               " WHERE UUID = '" << uuid << "' AND Diff > 0;";
+
+       db_manager::execute(0, query.str().c_str(), this);
+}
+
+void ctx::media_content_monitor::on_query_result_received(unsigned int query_id, int error, std::vector<json>& records)
+{
+       IF_FAIL_VOID(!records.empty());
+
+       int media_type = 0;
+       records[0].get(NULL, CX_MEDIA_TYPE, &media_type);
+
+       insert_log(media_type);
+}
+
+void ctx::media_content_monitor::insert_log(int media_type)
+{
+       int system_volume = -1, media_volume = -1, audiojack = -1;
+
+       json data;
+       data.set(NULL, CX_MEDIA_TYPE, media_type);
+
+       if (ctx::system_info::get_audio_jack_state(&audiojack))
+               data.set(NULL, STATS_AUDIO_JACK, audiojack);
+
+       if (ctx::system_info::get_volume(&system_volume, &media_volume)) {
+               data.set(NULL, STATS_SYSTEM_VOLUME, system_volume);
+               data.set(NULL, STATS_MEDIA_VOLUME, media_volume);
+       }
+
+       db_manager::insert(0, MEDIA_TABLE_NAME, data, NULL);
+}
diff --git a/src/media/media_content_monitor.h b/src/media/media_content_monitor.h
new file mode 100644 (file)
index 0000000..0c7dbfd
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONTEXT_MEDIA_CONTENT_MONITOR_H__
+#define __CONTEXT_MEDIA_CONTENT_MONITOR_H__
+
+#include <media_content.h>
+#include <db_listener_iface.h>
+
+namespace ctx {
+
+       class media_content_monitor : public db_listener_iface {
+       private:
+               bool started;
+               bool start_monitoring();
+               void stop_monitoring();
+
+               void update_play_count(const char *uuid, int type, int count);
+               void insert_log(int media_type);
+
+               void on_creation_result_received(unsigned int query_id, int error) {}
+               void on_insertion_result_received(unsigned int query_id, int error, int64_t row_id) {}
+               void on_query_result_received(unsigned int query_id, int error, std::vector<json>& records);
+
+               static void on_media_content_db_updated(media_content_error_e error, int pid,
+                               media_content_db_update_item_type_e update_item,
+                               media_content_db_update_type_e update_type,
+                               media_content_type_e media_type,
+                               char *uuid, char *path, char *mime_type, void *user_data);
+
+       public:
+               media_content_monitor();
+               ~media_content_monitor();
+       };
+
+}      /* namespace ctx */
+
+#endif
index 780325e..44939cc 100644 (file)
@@ -21,6 +21,9 @@
 #include <media_statistics_provider.h>
 #include "media_stats_types.h"
 #include "db_handle.h"
+#include "media_content_monitor.h"
+
+static ctx::media_content_monitor *content_mon = NULL;
 
 EXTAPI ctx::media_statistics_provider::media_statistics_provider()
 {
@@ -28,14 +31,15 @@ EXTAPI ctx::media_statistics_provider::media_statistics_provider()
 
 EXTAPI ctx::media_statistics_provider::~media_statistics_provider()
 {
+       delete content_mon;
+       content_mon = NULL;
 }
 
 bool ctx::media_statistics_provider::init()
 {
-       context_manager::register_provider(MEDIA_SUBJ_START_MUSIC, this);
-       context_manager::register_provider(MEDIA_SUBJ_STOP_MUSIC, this);
-       context_manager::register_provider(MEDIA_SUBJ_START_VIDEO, this);
-       context_manager::register_provider(MEDIA_SUBJ_STOP_VIDEO, this);
+       content_mon = new(std::nothrow) ctx::media_content_monitor();
+       IF_FAIL_RETURN_TAG(content_mon, false, _E, "Memory allocation failed");
+
        context_manager::register_provider(MEDIA_SUBJ_PEAK_TIME_FOR_MUSIC, this);
        context_manager::register_provider(MEDIA_SUBJ_PEAK_TIME_FOR_VIDEO, this);
        context_manager::register_provider(MEDIA_SUBJ_COMMON_SETTING_FOR_MUSIC, this);
@@ -87,19 +91,5 @@ int ctx::media_statistics_provider::read(const char* subject, ctx::json option,
 
 int ctx::media_statistics_provider::write(const char* subject, ctx::json data, ctx::json* request_result, const char* zone)
 {
-       if (!STR_EQ(zone, zone_util::default_zone())) {
-               _D("Not supported in the current zone '%s'", zone);
-               return ERR_NOT_SUPPORTED;
-       }
-
-       media_db_handle *handle = new(std::nothrow) media_db_handle(zone);
-       IF_FAIL_RETURN_TAG(handle, ERR_OPERATION_FAILED, _E, "Memory allocation failed");
-
-       int err = handle->write(subject, data);
-       if (err != ERR_NONE) {
-               delete handle;
-               return err;
-       }
-
-       return ERR_NONE;
+       return ERR_NOT_SUPPORTED;
 }
index 39df12c..f70e05a 100644 (file)
 #define __CONTEXT_MEDIA_STATS_TYPES_H__
 
 #include <common_types.h>
-
-#define MEDIA_SUBJ_START_MUSIC "music/event/start"
-#define MEDIA_SUBJ_STOP_MUSIC  "music/event/stop"
-#define MEDIA_SUBJ_START_VIDEO "video/event/start"
-#define MEDIA_SUBJ_STOP_VIDEO  "video/event/stop"
-
 #define MEDIA_SUBJ_PEAK_TIME_FOR_MUSIC         "music/history/peak_time"
 #define MEDIA_SUBJ_PEAK_TIME_FOR_VIDEO         "video/history/peak_time"
 #define MEDIA_SUBJ_COMMON_SETTING_FOR_MUSIC    "music/history/common_setting"
 
 #define MEDIA_TABLE_NAME       "Log_MediaPlayback"
 #define MEDIA_TABLE_COLUMNS \
-       "AppId TEXT NOT NULL, MediaType INTEGER NOT NULL, Action INTEGER NOT NULL, " \
+       "MediaType INTEGER NOT NULL, " \
        "SystemVolume INTEGER, MediaVolume INTEGER, AudioJack INTEGER, " \
        "UTC TIMESTAMP DEFAULT (strftime('%s', 'now')), " \
        "LocalTime TIMESTAMP DEFAULT (strftime('%s', 'now', 'localtime'))"
 
-#define MEDIA_TYPE             "MediaType"
-#define MEDIA_ACTION   "Action"
+#define MEDIA_PLAYCOUNT_TABLE_SCHEMA \
+       "CREATE TABLE IF NOT EXISTS Log_MediaPlayCount" \
+       " (UUID TEXT NOT NULL PRIMARY KEY, MediaType INTEGER NOT NULL," \
+       " Count INTEGER DEFAULT 0, Diff INTEGER DEFAULT 0)"
+
+#define CX_MEDIA_TYPE          "MediaType"
 
 enum media_type_e {
        MEDIA_TYPE_MUSIC = 1,
        MEDIA_TYPE_VIDEO,
 };
 
-enum media_action_e {
-       MEDIA_ACTION_START = 1,
-       MEDIA_ACTION_STOP,
-};
-
 #endif
diff --git a/src/media_dummy/media_stats_provider.cpp b/src/media_dummy/media_stats_provider.cpp
new file mode 100644 (file)
index 0000000..047cf77
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <types_internal.h>
+#include <json.h>
+#include <media_statistics_provider.h>
+
+EXTAPI ctx::media_statistics_provider::media_statistics_provider()
+{
+}
+
+EXTAPI ctx::media_statistics_provider::~media_statistics_provider()
+{
+}
+
+bool ctx::media_statistics_provider::init()
+{
+       return true;
+}
+
+bool ctx::media_statistics_provider::is_supported(const char* subject, const char* zone)
+{
+       return false;
+}
+
+int ctx::media_statistics_provider::subscribe(const char* subject, ctx::json option, ctx::json* request_result, const char* zone)
+{
+       return ERR_NOT_SUPPORTED;
+}
+
+int ctx::media_statistics_provider::unsubscribe(const char* subject, ctx::json option, const char* zone)
+{
+       return ERR_NOT_SUPPORTED;
+}
+
+int ctx::media_statistics_provider::read(const char* subject, ctx::json option, ctx::json* request_result, const char* zone)
+{
+       return ERR_NOT_SUPPORTED;
+}
+
+int ctx::media_statistics_provider::write(const char* subject, ctx::json data, ctx::json* request_result, const char* zone)
+{
+       return ERR_NOT_SUPPORTED;
+}