e989ab79dbba179a45f25109583d4ace8d43fb7e
[platform/core/context/context-provider.git] / src / my-place / facade / UserPlaces.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <ctime>
18 #include <memory>
19 #include <sstream>
20 #include <Types.h>
21 #include "UserPlaces.h"
22 #include <MyPlaceTypes.h>
23 #include <gmodule.h>
24 #include <DatabaseManager.h>
25 #include <string>
26
27 #define SO_PATH _LIBDIR_ "/context-service/libctx-prvd-my-place-places-detector.so"
28
29 typedef void (*places_detector_t)();
30
31 #define __GET_PLACES_QUERY "SELECT "\
32         PLACE_COLUMN_CATEG_ID ", "\
33         PLACE_COLUMN_CATEG_CONFIDENCE ", "\
34         PLACE_COLUMN_NAME ", "\
35         PLACE_COLUMN_LOCATION_VALID ", "\
36         PLACE_COLUMN_LOCATION_LATITUDE ", "\
37         PLACE_COLUMN_LOCATION_LONGITUDE ", "\
38         PLACE_COLUMN_LOCATION_ACCURACY ", "\
39         PLACE_COLUMN_WIFI_APS ", "\
40         PLACE_COLUMN_CREATE_DATE \
41         " FROM " PLACE_TABLE
42
43 #define __GET_WIFI_APS_MAP_QUERY "SELECT "\
44         WIFI_APS_MAP_COLUMN_MAC ", "\
45         WIFI_APS_MAP_COLUMN_NETWORK_NAME \
46         " FROM " WIFI_APS_MAP_TABLE
47
48 #define __MYPLACE_SETTINGS_TABLE_COLUMNS \
49         MYPLACE_SETTINGS_COLUMN_KEY " TEXT NOT NULL UNIQUE, "\
50         MYPLACE_SETTINGS_COLUMN_VALUE " TEXT NOT NULL"\
51
52 #define __GET_USER_CONSENT_QUERY "SELECT "\
53         MYPLACE_SETTINGS_COLUMN_VALUE \
54         " FROM " MYPLACE_SETTINGS_TABLE \
55         " WHERE " MYPLACE_SETTINGS_COLUMN_KEY \
56         "='" MYPLACE_SETTING_KEY_USER_CONSENT "';"
57
58 ctx::UserPlaces::UserPlaces(PlaceRecogMode energyMode):
59         __visitDetector(nullptr),
60         __timerId(-1),
61         __started(false),
62         __energyMode(energyMode)
63 {
64         _D("");
65         __dbCreateMyPlaceSettingsTable();
66         if (getConsent())
67                 __start();
68 }
69
70 ctx::UserPlaces::~UserPlaces()
71 {
72         __stop();
73 };
74
75 ctx::Json ctx::UserPlaces::getPlaces()
76 {
77         std::vector<Json> records = __dbGetPlaces();
78         std::map<std::string, std::string> wifiAPsMap = __dbGetWifiAPsMap();
79         std::vector<std::shared_ptr<Place>> places = __placesFromJsons(records, wifiAPsMap);
80         return UserPlaces::__composeJson(places);
81 }
82
83 ctx::Json ctx::UserPlaces::__composeJson(std::vector<std::shared_ptr<Place>> places)
84 {
85         ctx::Json data;
86         for (std::shared_ptr<ctx::Place> place : places) {
87                 ctx::Json placeJson;
88                 placeJson.set(NULL, PLACE_CATEG_ID, static_cast<int>(place->categId));
89                 placeJson.set(NULL, PLACE_CATEG_CONFIDENCE, static_cast<double>(place->categConfidence));
90                 placeJson.set(NULL, PLACE_NAME, place->name);
91                 if (place->locationValid) {
92                         ctx::Json locationJson;
93                         locationJson.set(NULL, PLACE_LOCATION_LATITUDE, static_cast<double>(place->location.latitude));
94                         locationJson.set(NULL, PLACE_LOCATION_LONGITUDE, static_cast<double>(place->location.longitude));
95                         locationJson.set(NULL, PLACE_LOCATION_ACCURACY, static_cast<double>(place->location.accuracy));
96                         placeJson.set(NULL, PLACE_LOCATION, locationJson);
97                 }
98                 if (place->wifiAps.size()) {
99                         ctx::Json wifiApsListJson;
100                         for (std::pair<std::string, std::string> ap : place->wifiAps) {
101                                 ctx::Json wifiApJson;
102                                 wifiApJson.set(NULL, PLACE_WIFI_AP_MAC, ap.first);
103                                 wifiApJson.set(NULL, PLACE_WIFI_AP_NETWORK_NAME, ap.second);
104                                 wifiApsListJson.append(NULL, PLACE_WIFI_APS, wifiApJson);
105                         }
106                         placeJson.set(NULL, PLACE_WIFI_APS, wifiApsListJson);
107                 }
108                 placeJson.set(NULL, PLACE_CREATE_DATE, static_cast<int64_t>(place->createDate));
109                 data.append(NULL, PLACE_DATA_READ, placeJson);
110         }
111         return data;
112 }
113
114 void ctx::UserPlaces::setMode(PlaceRecogMode energyMode)
115 {
116         __energyMode = energyMode;
117         if (__visitDetector)
118                 __visitDetector->setMode(energyMode);
119 }
120
121 bool ctx::UserPlaces::onTimerExpired(int timerId)
122 {
123         _D("Try to detect places from user visits");
124         GModule *soHandle = g_module_open(SO_PATH, G_MODULE_BIND_LAZY);
125         IF_FAIL_RETURN_TAG(soHandle, true, _E, "%s", g_module_error());
126
127         gpointer symbol;
128         if (!g_module_symbol(soHandle, "detectPlaces", &symbol) || symbol == NULL) {
129                 _E("%s", g_module_error());
130                 g_module_close(soHandle);
131                 return true;
132         }
133
134         places_detector_t detectPlaces = reinterpret_cast<places_detector_t>(symbol);
135
136         detectPlaces();
137         g_module_close(soHandle);
138         return true;
139 }
140
141 std::vector<ctx::Json> ctx::UserPlaces::__dbGetPlaces()
142 {
143         std::vector<Json> records;
144         DatabaseManager dbManager;
145         bool ret = dbManager.executeSync(__GET_PLACES_QUERY, &records);
146         _D("load places execute query result: %s", ret ? "SUCCESS" : "FAIL");
147         return records;
148 }
149
150 std::map<std::string, std::string> ctx::UserPlaces::__dbGetWifiAPsMap()
151 {
152         std::vector<Json> records;
153         std::map<std::string, std::string> wifiAPsMap;
154         DatabaseManager dbManager;
155         bool ret = dbManager.executeSync(__GET_WIFI_APS_MAP_QUERY, &records);
156         // TODO: add return statements if db fail
157         _D("load Wifi APs map (size = %d), result: %s", records.size(), ret ? "SUCCESS" : "FAIL");
158         std::string mac = "";
159         std::string networkName = "";
160         for (Json record : records) {
161                 record.get(NULL, WIFI_APS_MAP_COLUMN_MAC, &mac);
162                 record.get(NULL, WIFI_APS_MAP_COLUMN_NETWORK_NAME, &networkName);
163                 wifiAPsMap.insert(std::pair<std::string, std::string>(mac, networkName));
164         }
165         return wifiAPsMap;
166 }
167
168 std::shared_ptr<ctx::Place> ctx::UserPlaces::__placeFromJson(Json &row, std::map<std::string, std::string> &wifiAPsMap)
169 {
170         std::shared_ptr<Place> place = std::make_shared<Place>();
171         __placeCategoryFromJson(row, *place);
172         row.get(NULL, PLACE_COLUMN_NAME, &(place->name));
173         __placeLocationFromJson(row, *place);
174         __placeWifiAPsFromJson(row, wifiAPsMap, *place);
175         __placeCreateDateFromJson(row, *place);
176         _D("db_result: categId: %d; place: name: %s; locationValid: %d; latitude: %lf, longitude: %lf, createDate: %d", place->categId, place->name.c_str(), place->locationValid, place->location.latitude, place->location.longitude, place->createDate);
177         return place;
178 }
179
180 void ctx::UserPlaces::__placeCategoryFromJson(Json &row, ctx::Place &place)
181 {
182         int categId;
183         row.get(NULL, PLACE_COLUMN_CATEG_ID, &categId);
184         // This is due to the fact the JSON module API interface doesn't handle enum
185         place.categId = static_cast<PlaceCategId>(categId);
186 }
187
188 void ctx::UserPlaces::__placeLocationFromJson(Json &row, ctx::Place &place)
189 {
190         int locationValidInt;
191         row.get(NULL, PLACE_COLUMN_LOCATION_VALID, &locationValidInt);
192         place.locationValid = (bool) locationValidInt;
193         row.get(NULL, PLACE_COLUMN_LOCATION_LATITUDE, &(place.location.latitude));
194         row.get(NULL, PLACE_COLUMN_LOCATION_LONGITUDE, &(place.location.longitude));
195         row.get(NULL, PLACE_COLUMN_LOCATION_ACCURACY, &(place.location.accuracy));
196 }
197
198 void ctx::UserPlaces::__placeWifiAPsFromJson(Json &row, std::map<std::string, std::string> &wifiAPsMap, ctx::Place &place)
199 {
200         std::string wifiAps;
201         row.get(NULL, PLACE_COLUMN_WIFI_APS, &wifiAps);
202         std::stringstream ss;
203         ss << wifiAps;
204         std::shared_ptr<MacSet> macSet = std::make_shared<MacSet>();
205         ss >> *macSet;
206         for (ctx::Mac mac : *macSet) {
207                 place.wifiAps.insert(std::pair<std::string, std::string>(mac, wifiAPsMap[mac]));
208         }
209 }
210
211 void ctx::UserPlaces::__placeCreateDateFromJson(Json &row, ctx::Place &place)
212 {
213         int createDate;
214         row.get(NULL, PLACE_COLUMN_CREATE_DATE, &(createDate));
215         // This is due to the fact the JSON module API interface doesn't handle time_t
216         place.createDate = static_cast<time_t>(createDate);
217 }
218
219 std::vector<std::shared_ptr<ctx::Place>> ctx::UserPlaces::__placesFromJsons(std::vector<Json>& records, std::map<std::string, std::string> &wifiAPsMap)
220 {
221         std::vector<std::shared_ptr<Place>> places;
222         _D("db_result: number of all places: %d", records.size());
223
224         for (Json &row : records) {
225                 std::shared_ptr<Place> place = __placeFromJson(row, wifiAPsMap);
226                 places.push_back(place);
227         }
228         _D("number of all places in vector: %d", places.size());
229         return places;
230 }
231
232 void ctx::UserPlaces::__dbCreateMyPlaceSettingsTable()
233 {
234         DatabaseManager dbManager;
235         bool ret = dbManager.createTable(0, MYPLACE_SETTINGS_TABLE, __MYPLACE_SETTINGS_TABLE_COLUMNS);
236         _D("db: Myplace setting Table Creation Result: %s", ret ? "SUCCESS" : "FAIL");
237 }
238
239 void ctx::UserPlaces::setConsent(bool consent)
240 {
241         _D("");
242         DatabaseManager dbManager;
243         std::vector<Json> records;
244         std::stringstream query;
245         query << "REPLACE INTO " MYPLACE_SETTINGS_TABLE \
246                         " ( " MYPLACE_SETTINGS_COLUMN_KEY ", " MYPLACE_SETTINGS_COLUMN_VALUE " )" \
247                         " VALUES ( '" MYPLACE_SETTING_KEY_USER_CONSENT "', '";
248         if (consent) {
249                 query << MYPLACE_SETTING_VALUE_TRUE;
250                 if (!__started)
251                         __start();
252         } else {
253                 query << MYPLACE_SETTING_VALUE_FALSE;
254                 if (__started)
255                         __stop();
256         }
257         query << "' );";
258
259         bool ret = dbManager.executeSync(query.str().c_str(), &records);
260         IF_FAIL_VOID_TAG(ret, _E, "Setting user consent (value = %d) to database failed", consent);
261 }
262
263 bool ctx::UserPlaces::getConsent()
264 {
265         _D("");
266         DatabaseManager dbManager;
267         std::vector<Json> records;
268         bool ret = dbManager.executeSync(__GET_USER_CONSENT_QUERY, &records);
269         IF_FAIL_RETURN_TAG(ret, MYPLACE_SETTING_USER_CONSENT_DEFAULT, _E, "Getting user consent from database failed");
270         if (records.size()) {
271                 std::string consentStr;
272                 records[0].get(NULL, MYPLACE_SETTINGS_COLUMN_VALUE, &consentStr);
273                 if (consentStr == MYPLACE_SETTING_VALUE_TRUE) {
274                         _D("User consent value from db: TRUE");
275                         return true;
276                 } else if (consentStr == MYPLACE_SETTING_VALUE_FALSE) {
277                         _D("User consent value from db: FALSE");
278                         return false;
279                 } else {
280                         _E("Unknown user consent value \"%s\" from db, it should be \"%s\" or \"%s\"",
281                                 consentStr.c_str(),
282                                 MYPLACE_SETTING_VALUE_TRUE,
283                                 MYPLACE_SETTING_VALUE_FALSE);
284                 }
285         }
286         // consent record empty or unknown value
287         setConsent(MYPLACE_SETTING_USER_CONSENT_DEFAULT);
288         return MYPLACE_SETTING_USER_CONSENT_DEFAULT;
289 }
290
291 void ctx::UserPlaces::__start()
292 {
293         _D("");
294         time_t now = std::time(nullptr);
295         __visitDetector = new(std::nothrow) VisitDetector(now, __energyMode);
296         if (__visitDetector == nullptr) {
297                 _E("Cannot initialize VisitDetector");
298                 return;
299         }
300         __timerId = __timerManager.setAt( // execute once every night
301                         PLACES_DETECTOR_TASK_START_HOUR,
302                         PLACES_DETECTOR_TASK_START_MINUTE,
303                         DayOfWeek::EVERYDAY,
304                         this);
305         if (__timerId < 0) {
306                 _E("timer set FAIL");
307                 return;
308         } else {
309                 _D("timer set SUCCESS");
310         }
311         __started = true;
312 }
313
314 void ctx::UserPlaces::__stop()
315 {
316         _D("");
317         if (__timerId >= 0) {
318                 __timerManager.remove(__timerId);
319                 __timerId = -1;
320         }
321         if (__visitDetector) {
322                 delete __visitDetector;
323                 __visitDetector = nullptr;
324         }
325         __started = false;
326 }