[my-place] Forgotten data to detected places database add.
[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         _J("returns ", data);
112         return data;
113 }
114
115 void ctx::UserPlaces::setMode(PlaceRecogMode energyMode)
116 {
117         __energyMode = energyMode;
118         if (__visitDetector)
119                 __visitDetector->setMode(energyMode);
120 }
121
122 bool ctx::UserPlaces::onTimerExpired(int timerId)
123 {
124         _D("Try to detect places from user visits");
125         GModule *soHandle = g_module_open(SO_PATH, G_MODULE_BIND_LAZY);
126         IF_FAIL_RETURN_TAG(soHandle, true, _E, "%s", g_module_error());
127
128         gpointer symbol;
129         if (!g_module_symbol(soHandle, "detectPlaces", &symbol) || symbol == NULL) {
130                 _E("%s", g_module_error());
131                 g_module_close(soHandle);
132                 return true;
133         }
134
135         places_detector_t detectPlaces = reinterpret_cast<places_detector_t>(symbol);
136
137         detectPlaces();
138         g_module_close(soHandle);
139         return true;
140 }
141
142 std::vector<ctx::Json> ctx::UserPlaces::__dbGetPlaces()
143 {
144         std::vector<Json> records;
145         DatabaseManager dbManager;
146         bool ret = dbManager.executeSync(__GET_PLACES_QUERY, &records);
147         _D("load places execute query result: %s", ret ? "SUCCESS" : "FAIL");
148         return records;
149 }
150
151 std::map<std::string, std::string> ctx::UserPlaces::__dbGetWifiAPsMap()
152 {
153         std::vector<Json> records;
154         std::map<std::string, std::string> wifiAPsMap;
155         DatabaseManager dbManager;
156         bool ret = dbManager.executeSync(__GET_WIFI_APS_MAP_QUERY, &records);
157         // TODO: add return statements if db fail
158         _D("load Wifi APs map (size = %d), result: %s", records.size(), ret ? "SUCCESS" : "FAIL");
159         std::string mac = "";
160         std::string networkName = "";
161         for (Json record : records) {
162                 record.get(NULL, WIFI_APS_MAP_COLUMN_MAC, &mac);
163                 record.get(NULL, WIFI_APS_MAP_COLUMN_NETWORK_NAME, &networkName);
164                 wifiAPsMap.insert(std::pair<std::string, std::string>(mac, networkName));
165         }
166         return wifiAPsMap;
167 }
168
169 std::shared_ptr<ctx::Place> ctx::UserPlaces::__placeFromJson(Json &row, std::map<std::string, std::string> &wifiAPsMap)
170 {
171         std::shared_ptr<Place> place = std::make_shared<Place>();
172         __placeCategoryFromJson(row, *place);
173         row.get(NULL, PLACE_COLUMN_NAME, &(place->name));
174         __placeLocationFromJson(row, *place);
175         __placeWifiAPsFromJson(row, wifiAPsMap, *place);
176         __placeCreateDateFromJson(row, *place);
177         _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);
178         return place;
179 }
180
181 void ctx::UserPlaces::__placeCategoryFromJson(Json &row, ctx::Place &place)
182 {
183         int categId;
184         row.get(NULL, PLACE_COLUMN_CATEG_ID, &categId);
185         // This is due to the fact the JSON module API interface doesn't handle enum
186         place.categId = static_cast<PlaceCategId>(categId);
187 }
188
189 void ctx::UserPlaces::__placeLocationFromJson(Json &row, ctx::Place &place)
190 {
191         int locationValidInt;
192         row.get(NULL, PLACE_COLUMN_LOCATION_VALID, &locationValidInt);
193         place.locationValid = (bool) locationValidInt;
194         row.get(NULL, PLACE_COLUMN_LOCATION_LATITUDE, &(place.location.latitude));
195         row.get(NULL, PLACE_COLUMN_LOCATION_LONGITUDE, &(place.location.longitude));
196         row.get(NULL, PLACE_COLUMN_LOCATION_ACCURACY, &(place.location.accuracy));
197 }
198
199 void ctx::UserPlaces::__placeWifiAPsFromJson(Json &row, std::map<std::string, std::string> &wifiAPsMap, ctx::Place &place)
200 {
201         std::string wifiAps;
202         row.get(NULL, PLACE_COLUMN_WIFI_APS, &wifiAps);
203         std::stringstream ss;
204         ss << wifiAps;
205         std::shared_ptr<MacSet> macSet = std::make_shared<MacSet>();
206         ss >> *macSet;
207         for (ctx::Mac mac : *macSet) {
208                 place.wifiAps.insert(std::pair<std::string, std::string>(mac, wifiAPsMap[mac]));
209         }
210 }
211
212 void ctx::UserPlaces::__placeCreateDateFromJson(Json &row, ctx::Place &place)
213 {
214         int createDate;
215         row.get(NULL, PLACE_COLUMN_CREATE_DATE, &(createDate));
216         // This is due to the fact the JSON module API interface doesn't handle time_t
217         place.createDate = static_cast<time_t>(createDate);
218 }
219
220 std::vector<std::shared_ptr<ctx::Place>> ctx::UserPlaces::__placesFromJsons(std::vector<Json>& records, std::map<std::string, std::string> &wifiAPsMap)
221 {
222         std::vector<std::shared_ptr<Place>> places;
223         _D("db_result: number of all places: %d", records.size());
224
225         for (Json &row : records) {
226                 std::shared_ptr<Place> place = __placeFromJson(row, wifiAPsMap);
227                 places.push_back(place);
228         }
229         _D("number of all places in vector: %d", places.size());
230         return places;
231 }
232
233 void ctx::UserPlaces::__dbCreateMyPlaceSettingsTable()
234 {
235         DatabaseManager dbManager;
236         bool ret = dbManager.createTable(0, MYPLACE_SETTINGS_TABLE, __MYPLACE_SETTINGS_TABLE_COLUMNS);
237         _D("db: Myplace setting Table Creation Result: %s", ret ? "SUCCESS" : "FAIL");
238 }
239
240 void ctx::UserPlaces::setConsent(bool consent)
241 {
242         _D("");
243         DatabaseManager dbManager;
244         std::vector<Json> records;
245         std::stringstream query;
246         query << "REPLACE INTO " MYPLACE_SETTINGS_TABLE \
247                         " ( " MYPLACE_SETTINGS_COLUMN_KEY ", " MYPLACE_SETTINGS_COLUMN_VALUE " )" \
248                         " VALUES ( '" MYPLACE_SETTING_KEY_USER_CONSENT "', '";
249         if (consent) {
250                 query << MYPLACE_SETTING_VALUE_TRUE;
251                 if (!__started)
252                         __start();
253         } else {
254                 query << MYPLACE_SETTING_VALUE_FALSE;
255                 if (__started)
256                         __stop();
257         }
258         query << "' );";
259
260         bool ret = dbManager.executeSync(query.str().c_str(), &records);
261         IF_FAIL_VOID_TAG(ret, _E, "Setting user consent (value = %d) to database failed", consent);
262 }
263
264 bool ctx::UserPlaces::getConsent()
265 {
266         _D("");
267         DatabaseManager dbManager;
268         std::vector<Json> records;
269         bool ret = dbManager.executeSync(__GET_USER_CONSENT_QUERY, &records);
270         IF_FAIL_RETURN_TAG(ret, MYPLACE_SETTING_USER_CONSENT_DEFAULT, _E, "Getting user consent from database failed");
271         if (records.size()) {
272                 std::string consentStr;
273                 records[0].get(NULL, MYPLACE_SETTINGS_COLUMN_VALUE, &consentStr);
274                 if (consentStr == MYPLACE_SETTING_VALUE_TRUE) {
275                         _D("User consent value from db: TRUE");
276                         return true;
277                 } else if (consentStr == MYPLACE_SETTING_VALUE_FALSE) {
278                         _D("User consent value from db: FALSE");
279                         return false;
280                 } else {
281                         _E("Unknown user consent value \"%s\" from db, it should be \"%s\" or \"%s\"",
282                                 consentStr.c_str(),
283                                 MYPLACE_SETTING_VALUE_TRUE,
284                                 MYPLACE_SETTING_VALUE_FALSE);
285                 }
286         }
287         // consent record empty or unknown value
288         setConsent(MYPLACE_SETTING_USER_CONSENT_DEFAULT);
289         return MYPLACE_SETTING_USER_CONSENT_DEFAULT;
290 }
291
292 void ctx::UserPlaces::__start()
293 {
294         _D("");
295         time_t now = std::time(nullptr);
296         __visitDetector = new(std::nothrow) VisitDetector(now, __energyMode);
297         if (__visitDetector == nullptr) {
298                 _E("Cannot initialize VisitDetector");
299                 return;
300         }
301         __timerId = __timerManager.setAt( // execute once every night
302                         PLACES_DETECTOR_TASK_START_HOUR,
303                         PLACES_DETECTOR_TASK_START_MINUTE,
304                         DayOfWeek::EVERYDAY,
305                         this);
306         if (__timerId < 0) {
307                 _E("timer set FAIL");
308                 return;
309         } else {
310                 _D("timer set SUCCESS");
311         }
312         __started = true;
313 }
314
315 void ctx::UserPlaces::__stop()
316 {
317         _D("");
318         if (__timerId >= 0) {
319                 __timerManager.remove(__timerId);
320                 __timerId = -1;
321         }
322         if (__visitDetector) {
323                 delete __visitDetector;
324                 __visitDetector = nullptr;
325         }
326         __started = false;
327 }