2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include <json/json.h>
21 #include <SharedUtil.h>
22 #include <job_scheduler_internal.h>
23 #include <job_scheduler_types_internal.h>
24 #include <context_trigger.h>
25 #include "PrivilegeChecker.h"
26 #include "ContextItem.h"
28 #define CTX_SCHED_URI_ALARM CTX_SCHED_URI_PREFIX "event/time"
29 #define CTX_SCHED_URI_CALL CTX_SCHED_URI_PREFIX "state/email"
30 #define CTX_SCHED_URI_EMAIL CTX_SCHED_URI_PREFIX "event/email"
31 #define CTX_SCHED_URI_MESSAGE CTX_SCHED_URI_PREFIX "event/message"
32 #define CTX_SCHED_URI_APP_FREQ CTX_SCHED_URI_PREFIX "stats/app"
33 #define CTX_SCHED_URI_COMM_FREQ CTX_SCHED_URI_PREFIX "stats/comm"
34 #define CTX_SCHED_URI_MUSIC_FREQ CTX_SCHED_URI_PREFIX "stats/music"
35 #define CTX_SCHED_URI_VIDEO_FREQ CTX_SCHED_URI_PREFIX "stats/video"
37 #define URI(x) CTX_SCHED_URI_##x
38 #define NAME(x) CTX_SCHED_ATTR_NAME_##x
40 ContextItem::ContextItem(int cx) :
46 bool ContextItem::allowed()
48 return PrivilegeChecker::hasPrivilege(__getPrivilege());
51 bool ContextItem::isValid(ctx_sched_job_context_h jobContext)
53 IF_FAIL_RETURN(jobContext, false);
55 struct MandatoryEntry {
57 std::vector<const char*> attributes;
60 static std::vector<MandatoryEntry> mandatories = {
61 { URI(ALARM), {NAME(TIME_OF_DAY)} },
62 { URI(GEOFENCE), {NAME(PLACE_ID)} },
63 { URI(APP_FREQ), {CONTEXT_TRIGGER_APP_ID} }
67 const char* serialized = ctx_sched_job_context_serialize(jobContext);
68 IF_FAIL_RETURN(serialized, false);
74 if (!reader.parse(serialized, jCtx)) {
78 } catch (const Json::Exception& e) {
79 _E("Exception: %s", e.what());
83 IF_FAIL_RETURN(jCtx.isMember("Attribute"), false);
85 Json::Value& attributes = jCtx["Attribute"];
87 for (auto& entry : mandatories) {
88 if (!STR_EQ(entry.uri, getUri()))
91 for (auto& mandatoryAttr : entry.attributes) {
92 // The mandatory attribute should be exist
93 if (!attributes.isMember(mandatoryAttr))
96 // If exist, at least one target value needs to be designated
97 if (attributes[mandatoryAttr]["Target"].size() == 0)
107 bool ContextItem::isValidData(const char* attribute)
109 return (isValidData(attribute, 1) || isValidData(attribute, static_cast<const char*>(NULL)));
112 bool ContextItem::isValidData(const char* attribute, int value)
114 static std::vector<IntAttributeRange> attributeRanges = {
115 { URI(ALARM), NAME(TIME_OF_DAY), 0, 1439 },
116 { URI(TIME), NAME(TIME_OF_DAY), 0, 1439 },
117 { URI(TIME), NAME(DAY_OF_MONTH), 1, 31 },
118 { URI(BATTERY), NAME(IS_CHARGING), 0, 1 },
119 { URI(CHARGER), NAME(IS_CONNECTED), 0, 1 },
120 { URI(EARJACK), NAME(IS_CONNECTED), 0, 1 },
121 { URI(USB), NAME(IS_CONNECTED), 0, 1 },
122 { URI(POWERSAVE), NAME(IS_ENABLED), 0, 1 }
123 //TODO: unsupported items
126 _D("Verify %s, %d", attribute, value);
128 return __isValid(attributeRanges, attribute, value);
131 bool ContextItem::isValidData(const char* attribute, const char* value)
133 static std::vector<StrAttributeValues> attributeValues = {
134 { URI(ALARM), NAME(DAY_OF_WEEK), {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Weekday", "Weekend"} },
135 { URI(TIME), NAME(DAY_OF_WEEK), {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Weekday", "Weekend"} },
136 { URI(BATTERY), NAME(LEVEL), {"Empty", "Critical", "Low", "Normal", "High", "Full"} },
137 { URI(GEOFENCE), NAME(EVENT), {"In", "Out"} },
138 { URI(GPS), NAME(STATE), {"Disabled", "Searching", "Connected"} },
139 { URI(EARJACK), NAME(TYPE), {"Normal", "Headset", "Bluetooth"} },
140 { URI(WIFI), NAME(STATE), {"Disabled", "Unconnected", "Connected"} },
141 { URI(WIFI), NAME(BSSID), {} },
142 { URI(STATIONARY), NAME(EVENT), {"Detected"} },
143 { URI(WALKING), NAME(EVENT), {"Detected"} },
144 { URI(RUNNING), NAME(EVENT), {"Detected"} },
145 { URI(IN_VEHICLE), NAME(EVENT), {"Detected"} },
146 { URI(CONTACTS_DB), NAME(EVENT), {"Changed"} },
147 { URI(CONTACTS_DB), NAME(TYPE), {"MyProfile", "Person"} }
148 //TODO: unsupported items
151 _D("Verify %s, %s", attribute, value);
153 return __isValid(attributeValues, attribute, value);
156 bool ContextItem::isValidOption(const char* attribute)
158 return (isValidOption(attribute, 1) || isValidOption(attribute, static_cast<const char*>(NULL)));
161 bool ContextItem::isValidOption(const char* attribute, int value)
163 static std::vector<IntAttributeRange> attributeRanges = {
164 { URI(GEOFENCE), NAME(PLACE_ID), 1, INT_MAX }
165 //TODO: unsupported items
168 _D("Verify %s, %d", attribute, value);
170 return __isValid(attributeRanges, attribute, value);
173 bool ContextItem::isValidOption(const char* attribute, const char* value)
175 static std::vector<StrAttributeValues> attributeValues = {
176 { URI(STATIONARY), NAME(ACCURACY), {"Low", "Normal", "High"} },
177 { URI(WALKING), NAME(ACCURACY), {"Low", "Normal", "High"} },
178 { URI(RUNNING), NAME(ACCURACY), {"Low", "Normal", "High"} },
179 { URI(IN_VEHICLE), NAME(ACCURACY), {"Low", "Normal", "High"} }
180 //TODO: unsupported items
183 _D("Verify %s, %s", attribute, value);
185 return __isValid(attributeValues, attribute, value);
188 bool ContextItem::__isValid(const std::vector<IntAttributeRange>& attributeRanges, const char* attribute, int value)
190 for (auto& range : attributeRanges) {
191 if (!STR_EQ(range.uri, getUri()))
194 if (!STR_EQ(range.attribute, attribute))
197 if (value < range.min || value > range.max)
206 bool ContextItem::__isValid(const std::vector<StrAttributeValues>& attributeValues, const char* attribute, const char* value)
208 for (auto& values : attributeValues) {
209 if (!STR_EQ(values.uri, getUri()))
212 if (!STR_EQ(values.attribute, attribute))
215 // NULL value is a wildcard
219 // Accept any strings
220 if (values.values.empty())
223 auto it = std::find_if(values.values.begin(), values.values.end(),
224 [&value](const char* validValue)->bool {
225 return STR_EQ(value, validValue);
228 if (it == values.values.end())
237 EventItem::EventItem(int event) :
242 bool EventItem::deprecated()
245 case CONTEXT_TRIGGER_EVENT_TIME:
246 case CONTEXT_TRIGGER_EVENT_POWER_SAVING_MODE:
247 case CONTEXT_TRIGGER_EVENT_CALL:
248 case CONTEXT_TRIGGER_EVENT_EMAIL:
249 case CONTEXT_TRIGGER_EVENT_MESSAGE:
256 const char* EventItem::getUri()
258 static const std::map<int, const char*> uriMap = {
259 {CONTEXT_TRIGGER_EVENT_TIME, URI(ALARM)},
260 {CONTEXT_TRIGGER_EVENT_BATTERY, URI(BATTERY)},
261 {CONTEXT_TRIGGER_EVENT_CHARGER, URI(CHARGER)},
262 {CONTEXT_TRIGGER_EVENT_GPS, URI(GPS)},
263 {CONTEXT_TRIGGER_EVENT_HEADPHONE, URI(EARJACK)},
264 {CONTEXT_TRIGGER_EVENT_POWER_SAVING_MODE, URI(POWERSAVE)},
265 {CONTEXT_TRIGGER_EVENT_USB, URI(USB)},
266 {CONTEXT_TRIGGER_EVENT_WIFI, URI(WIFI)},
267 {CONTEXT_TRIGGER_EVENT_CALL, URI(CALL)},
268 {CONTEXT_TRIGGER_EVENT_EMAIL, URI(EMAIL)},
269 {CONTEXT_TRIGGER_EVENT_MESSAGE, URI(MESSAGE)},
270 {CONTEXT_TRIGGER_EVENT_CONTACTS, URI(CONTACTS_DB)},
271 {CONTEXT_TRIGGER_EVENT_ACTIVITY_STATIONARY, URI(STATIONARY)},
272 {CONTEXT_TRIGGER_EVENT_ACTIVITY_WALKING, URI(WALKING)},
273 {CONTEXT_TRIGGER_EVENT_ACTIVITY_RUNNING, URI(RUNNING)},
274 {CONTEXT_TRIGGER_EVENT_ACTIVITY_IN_VEHICLE, URI(IN_VEHICLE)},
275 {CONTEXT_TRIGGER_EVENT_PLACE, URI(GEOFENCE)}
278 if (__uri) return __uri;
280 auto it = uriMap.find(__context);
282 if (it == uriMap.end())
285 return (__uri = it->second);
288 const char* EventItem::__getPrivilege()
290 if (CONTEXT_TRIGGER_EVENT_TIME == __context)
291 return "http://tizen.org/privilege/alarm.set";
293 if (CONTEXT_TRIGGER_EVENT_WIFI == __context)
294 return "http://tizen.org/privilege/network.get";
296 if (CONTEXT_TRIGGER_EVENT_CALL == __context)
297 return "http://tizen.org/privilege/telephony";
299 if (CONTEXT_TRIGGER_EVENT_MESSAGE == __context)
300 return "http://tizen.org/privilege/message.read";
302 if (CONTEXT_TRIGGER_EVENT_CONTACTS == __context)
303 return "http://tizen.org/privilege/contact.read";
305 if (CONTEXT_TRIGGER_EVENT_PLACE == __context)
306 return "http://tizen.org/privilege/location";
311 ConditionItem::ConditionItem(int cond) :
316 bool ConditionItem::deprecated()
319 case CONTEXT_TRIGGER_CONDITION_POWER_SAVING_MODE:
320 case CONTEXT_TRIGGER_CONDITION_CALL:
321 case CONTEXT_TRIGGER_CONDITION_APP_USE_FREQUENCY:
322 case CONTEXT_TRIGGER_CONDITION_COMMUNICATION_FREQUENCY:
323 case CONTEXT_TRIGGER_CONDITION_MUSIC_PLAYBACK_FREQUENCY:
324 case CONTEXT_TRIGGER_CONDITION_VIDEO_PLAYBACK_FREQUENCY:
331 const char* ConditionItem::getUri()
333 static const std::map<int, const char*> uriMap = {
334 {CONTEXT_TRIGGER_CONDITION_TIME, URI(TIME)},
335 {CONTEXT_TRIGGER_CONDITION_BATTERY, URI(BATTERY)},
336 {CONTEXT_TRIGGER_CONDITION_CHARGER, URI(CHARGER)},
337 {CONTEXT_TRIGGER_CONDITION_GPS, URI(GPS)},
338 {CONTEXT_TRIGGER_CONDITION_HEADPHONE, URI(EARJACK)},
339 {CONTEXT_TRIGGER_CONDITION_POWER_SAVING_MODE, URI(POWERSAVE)},
340 {CONTEXT_TRIGGER_CONDITION_USB, URI(USB)},
341 {CONTEXT_TRIGGER_CONDITION_WIFI, URI(WIFI)},
342 {CONTEXT_TRIGGER_CONDITION_CALL, URI(CALL)},
343 {CONTEXT_TRIGGER_CONDITION_APP_USE_FREQUENCY, URI(APP_FREQ)},
344 {CONTEXT_TRIGGER_CONDITION_COMMUNICATION_FREQUENCY, URI(COMM_FREQ)},
345 {CONTEXT_TRIGGER_CONDITION_MUSIC_PLAYBACK_FREQUENCY, URI(MUSIC_FREQ)},
346 {CONTEXT_TRIGGER_CONDITION_VIDEO_PLAYBACK_FREQUENCY, URI(VIDEO_FREQ)}
349 if (__uri) return __uri;
351 auto it = uriMap.find(__context);
353 if (it == uriMap.end())
356 return (__uri = it->second);
359 const char* ConditionItem::__getPrivilege()
361 if (CONTEXT_TRIGGER_CONDITION_WIFI == __context)
362 return "http://tizen.org/privilege/network.get";
364 if (CONTEXT_TRIGGER_CONDITION_CALL == __context)
365 return "http://tizen.org/privilege/telephony";
367 if (CONTEXT_TRIGGER_CONDITION_APP_USE_FREQUENCY == __context)
368 return "http://tizen.org/privilege/apphistory.read";
370 if (CONTEXT_TRIGGER_CONDITION_COMMUNICATION_FREQUENCY == __context)
371 return "http://tizen.org/privilege/callhistory.read";
373 if (CONTEXT_TRIGGER_CONDITION_MUSIC_PLAYBACK_FREQUENCY == __context)
374 return "http://tizen.org/privilege/mediahistory.read";
376 if (CONTEXT_TRIGGER_CONDITION_VIDEO_PLAYBACK_FREQUENCY == __context)
377 return "http://tizen.org/privilege/mediahistory.read";