*/
#include <map>
+#include <vector>
+#include <algorithm>
+#include <json/json.h>
+#include <SharedUtil.h>
+#include <job_scheduler_internal.h>
#include <job_scheduler_types_internal.h>
#include <context_trigger.h>
#include "PrivilegeChecker.h"
#include "ContextItem.h"
+#define CTX_SCHED_URI_ALARM CTX_SCHED_URI_PREFIX "event/time"
+#define CTX_SCHED_URI_CALL CTX_SCHED_URI_PREFIX "state/email"
+#define CTX_SCHED_URI_EMAIL CTX_SCHED_URI_PREFIX "event/email"
+#define CTX_SCHED_URI_MESSAGE CTX_SCHED_URI_PREFIX "event/message"
+#define CTX_SCHED_URI_APP_FREQ CTX_SCHED_URI_PREFIX "stats/app"
+#define CTX_SCHED_URI_COMM_FREQ CTX_SCHED_URI_PREFIX "stats/comm"
+#define CTX_SCHED_URI_MUSIC_FREQ CTX_SCHED_URI_PREFIX "stats/music"
+#define CTX_SCHED_URI_VIDEO_FREQ CTX_SCHED_URI_PREFIX "stats/video"
+
#define URI(x) CTX_SCHED_URI_##x
#define NAME(x) CTX_SCHED_ATTR_NAME_##x
-#define VALUE(x) CTX_SCHED_ATTR_VALUE_##x
ContextItem::ContextItem(int cx) :
- __context(cx)
+ __context(cx),
+ __uri(NULL)
{
}
bool ContextItem::isValid(ctx_sched_job_context_h jobContext)
{
- //TODO: Check if the context has all mandatory fields
+ IF_FAIL_RETURN(jobContext, false);
+
+ struct MandatoryEntry {
+ const char* uri;
+ std::vector<const char*> attributes;
+ };
+
+ static std::vector<MandatoryEntry> mandatories = {
+ { URI(ALARM), {NAME(TIME_OF_DAY)} },
+ { URI(GEOFENCE), {NAME(PLACE_ID)} },
+ { URI(APP_FREQ), {CONTEXT_TRIGGER_APP_ID} }
+ //TODO
+ };
+
+ const char* serialized = ctx_sched_job_context_serialize(jobContext);
+ IF_FAIL_RETURN(serialized, false);
+
+ Json::Value jCtx;
+
+ try {
+ Json::Reader reader;
+ if (!reader.parse(serialized, jCtx)) {
+ _E("Parsing failed");
+ return false;
+ }
+ } catch (const Json::Exception& e) {
+ _E("Exception: %s", e.what());
+ return false;
+ }
+
+ IF_FAIL_RETURN(jCtx.isMember("Attribute"), false);
+
+ Json::Value& attributes = jCtx["Attribute"];
+
+ for (auto& entry : mandatories) {
+ if (!STR_EQ(entry.uri, getUri()))
+ continue;
+
+ for (auto& mandatoryAttr : entry.attributes) {
+ // The mandatory attribute should be exist
+ if (!attributes.isMember(mandatoryAttr))
+ return false;
+
+ // If exist, at least one target value needs to be designated
+ if (attributes[mandatoryAttr]["Target"].size() == 0)
+ return false;
+ }
+
+ return true;
+ }
+
return true;
}
-bool ContextItem::isValid(const std::string& attribute)
+bool ContextItem::isValidData(const char* attribute)
{
- //TODO: Check if the attribute is valid for this __context
- return true;
+ return (isValidData(attribute, 1) || isValidData(attribute, static_cast<const char*>(NULL)));
}
-bool ContextItem::isValid(const std::string& attribute, int value)
+bool ContextItem::isValidData(const char* attribute, int value)
{
- //TODO: Check if the attribute & value pair is valid for this __context
- return true;
+ static std::vector<IntAttributeRange> attributeRanges = {
+ { URI(ALARM), NAME(TIME_OF_DAY), 0, 1439 },
+ { URI(TIME), NAME(TIME_OF_DAY), 0, 1439 },
+ { URI(TIME), NAME(DAY_OF_MONTH), 1, 31 },
+ { URI(BATTERY), NAME(IS_CHARGING), 0, 1 },
+ { URI(CHARGER), NAME(IS_CONNECTED), 0, 1 },
+ { URI(EARJACK), NAME(IS_CONNECTED), 0, 1 },
+ { URI(USB), NAME(IS_CONNECTED), 0, 1 },
+ { URI(POWERSAVE), NAME(IS_ENABLED), 0, 1 }
+ //TODO: unsupported items
+ };
+
+ _D("Verify %s, %d", attribute, value);
+
+ return __isValid(attributeRanges, attribute, value);
}
-bool ContextItem::isValid(const std::string& attribute, const std::string& value)
+bool ContextItem::isValidData(const char* attribute, const char* value)
{
- //TODO: Check if the attribute & value pair is valid for this __context
- return true;
+ static std::vector<StrAttributeValues> attributeValues = {
+ { URI(ALARM), NAME(DAY_OF_WEEK), {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Weekday", "Weekend"} },
+ { URI(TIME), NAME(DAY_OF_WEEK), {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Weekday", "Weekend"} },
+ { URI(BATTERY), NAME(LEVEL), {"Empty", "Critical", "Low", "Normal", "High", "Full"} },
+ { URI(GEOFENCE), NAME(EVENT), {"In", "Out"} },
+ { URI(GPS), NAME(STATE), {"Disabled","Searching","Connected"} },
+ { URI(EARJACK), NAME(TYPE), {"Normal", "Headset", "Bluetooth"} },
+ { URI(WIFI), NAME(STATE), {"Disabled","Unconnected","Connected"} },
+ { URI(WIFI), NAME(BSSID), {} },
+ { URI(STATIONARY), NAME(EVENT), {"Detected"} },
+ { URI(WALKING), NAME(EVENT), {"Detected"} },
+ { URI(RUNNING), NAME(EVENT), {"Detected"} },
+ { URI(IN_VEHICLE), NAME(EVENT), {"Detected"} },
+ { URI(CONTACTS_DB), NAME(EVENT), {"Changed"} },
+ { URI(CONTACTS_DB), NAME(TYPE), {"MyProfile", "Person"} }
+ //TODO: unsupported items
+ };
+
+ _D("Verify %s, %s", attribute, value);
+
+ return __isValid(attributeValues, attribute, value);
+}
+
+bool ContextItem::isValidOption(const char* attribute)
+{
+ return (isValidOption(attribute, 1) || isValidOption(attribute, static_cast<const char*>(NULL)));
+}
+
+bool ContextItem::isValidOption(const char* attribute, int value)
+{
+ static std::vector<IntAttributeRange> attributeRanges = {
+ { URI(GEOFENCE), NAME(PLACE_ID), 1, INT_MAX }
+ //TODO: unsupported items
+ };
+
+ _D("Verify %s, %d", attribute, value);
+
+ return __isValid(attributeRanges, attribute, value);
+}
+
+bool ContextItem::isValidOption(const char* attribute, const char* value)
+{
+ static std::vector<StrAttributeValues> attributeValues = {
+ { URI(STATIONARY), NAME(ACCURACY), {"Low", "Normal", "High"} },
+ { URI(WALKING), NAME(ACCURACY), {"Low", "Normal", "High"} },
+ { URI(RUNNING), NAME(ACCURACY), {"Low", "Normal", "High"} },
+ { URI(IN_VEHICLE), NAME(ACCURACY), {"Low", "Normal", "High"} }
+ //TODO: unsupported items
+ };
+
+ _D("Verify %s, %s", attribute, value);
+
+ return __isValid(attributeValues, attribute, value);
+}
+
+bool ContextItem::__isValid(const std::vector<IntAttributeRange>& attributeRanges, const char* attribute, int value)
+{
+ for (auto& range : attributeRanges) {
+ if (!STR_EQ(range.uri, getUri()))
+ continue;
+
+ if (!STR_EQ(range.attribute, attribute))
+ continue;
+
+ if (value < range.min || value > range.max)
+ return false;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool ContextItem::__isValid(const std::vector<StrAttributeValues>& attributeValues, const char* attribute, const char* value)
+{
+ for (auto& values : attributeValues) {
+ if (!STR_EQ(values.uri, getUri()))
+ continue;
+
+ if (!STR_EQ(values.attribute, attribute))
+ continue;
+
+ // NULL value is a wildcard
+ if (!value)
+ return true;
+
+ // Accept any strings
+ if (values.values.empty())
+ return true;
+
+ auto it = std::find_if(values.values.begin(), values.values.end(),
+ [&value](const char* validValue)->bool {
+ return STR_EQ(value, validValue);
+ });
+
+ if (it == values.values.end())
+ return false;
+
+ return true;
+ }
+
+ return false;
}
EventItem::EventItem(int event) :
const char* EventItem::getUri()
{
static const std::map<int, const char*> uriMap = {
- {CONTEXT_TRIGGER_EVENT_TIME, CTX_SCHED_URI_PREFIX "event/time"},
+ {CONTEXT_TRIGGER_EVENT_TIME, URI(ALARM)},
{CONTEXT_TRIGGER_EVENT_BATTERY, URI(BATTERY)},
{CONTEXT_TRIGGER_EVENT_CHARGER, URI(CHARGER)},
{CONTEXT_TRIGGER_EVENT_GPS, URI(GPS)},
{CONTEXT_TRIGGER_EVENT_POWER_SAVING_MODE, URI(POWERSAVE)},
{CONTEXT_TRIGGER_EVENT_USB, URI(USB)},
{CONTEXT_TRIGGER_EVENT_WIFI, URI(WIFI)},
- {CONTEXT_TRIGGER_EVENT_CALL, CTX_SCHED_URI_PREFIX "state/call"},
- {CONTEXT_TRIGGER_EVENT_EMAIL, CTX_SCHED_URI_PREFIX "event/email"},
- {CONTEXT_TRIGGER_EVENT_MESSAGE, CTX_SCHED_URI_PREFIX "event/message"},
+ {CONTEXT_TRIGGER_EVENT_CALL, URI(CALL)},
+ {CONTEXT_TRIGGER_EVENT_EMAIL, URI(EMAIL)},
+ {CONTEXT_TRIGGER_EVENT_MESSAGE, URI(MESSAGE)},
{CONTEXT_TRIGGER_EVENT_CONTACTS, URI(CONTACTS_DB)},
{CONTEXT_TRIGGER_EVENT_ACTIVITY_STATIONARY, URI(STATIONARY)},
{CONTEXT_TRIGGER_EVENT_ACTIVITY_WALKING, URI(WALKING)},
{CONTEXT_TRIGGER_EVENT_PLACE, URI(GEOFENCE)}
};
+ if (__uri) return __uri;
+
auto it = uriMap.find(__context);
if (it == uriMap.end())
return NULL;
- return it->second;
+ return (__uri = it->second);
}
const char* EventItem::__getPrivilege()
{CONTEXT_TRIGGER_CONDITION_POWER_SAVING_MODE, URI(POWERSAVE)},
{CONTEXT_TRIGGER_CONDITION_USB, URI(USB)},
{CONTEXT_TRIGGER_CONDITION_WIFI, URI(WIFI)},
- {CONTEXT_TRIGGER_CONDITION_CALL, CTX_SCHED_URI_PREFIX "state/call"},
- {CONTEXT_TRIGGER_CONDITION_APP_USE_FREQUENCY, CTX_SCHED_URI_PREFIX "stats/app"},
- {CONTEXT_TRIGGER_CONDITION_COMMUNICATION_FREQUENCY, CTX_SCHED_URI_PREFIX "stats/comm"},
- {CONTEXT_TRIGGER_CONDITION_MUSIC_PLAYBACK_FREQUENCY, CTX_SCHED_URI_PREFIX "stats/music"},
- {CONTEXT_TRIGGER_CONDITION_VIDEO_PLAYBACK_FREQUENCY, CTX_SCHED_URI_PREFIX "stats/video"}
+ {CONTEXT_TRIGGER_CONDITION_CALL, URI(CALL)},
+ {CONTEXT_TRIGGER_CONDITION_APP_USE_FREQUENCY, URI(APP_FREQ)},
+ {CONTEXT_TRIGGER_CONDITION_COMMUNICATION_FREQUENCY, URI(COMM_FREQ)},
+ {CONTEXT_TRIGGER_CONDITION_MUSIC_PLAYBACK_FREQUENCY, URI(MUSIC_FREQ)},
+ {CONTEXT_TRIGGER_CONDITION_VIDEO_PLAYBACK_FREQUENCY, URI(VIDEO_FREQ)}
};
+ if (__uri) return __uri;
+
auto it = uriMap.find(__context);
if (it == uriMap.end())
return NULL;
- return it->second;
+ return (__uri = it->second);
}
const char* ConditionItem::__getPrivilege()
ContextItem* contextItem = __get_context_item(entry);
IF_FAIL_RETURN(contextItem, E_FAILED);
- bool valid = contextItem->isValid(option_key, value);
+ bool valid = contextItem->isValidOption(option_key, value);
delete contextItem;
IF_FAIL_RETURN(valid, E_INV_RULE);
ContextItem* contextItem = __get_context_item(entry);
IF_FAIL_RETURN(contextItem, E_FAILED);
- bool valid = contextItem->isValid(option_key, value);
+ bool valid = contextItem->isValidOption(option_key, value);
delete contextItem;
IF_FAIL_RETURN(valid, E_INV_RULE);
IF_FAIL_RETURN(entry->category == CATEGORY_CONDITION, E_INV_RULE);
ConditionItem contextItem(entry->type);
- IF_FAIL_RETURN(contextItem.isValid(option_key), E_INV_RULE);
+ IF_FAIL_RETURN(contextItem.isValidOption(option_key), E_INV_RULE);
ctx_sched_job_context_prepare_attribute_str(entry->jobContext, option_key);
return ctx_sched_job_context_attribute_add_eq_str(entry->jobContext, option_key, event_data_key);
ContextItem* contextItem = __get_context_item(entry);
IF_FAIL_RETURN(contextItem, E_FAILED);
- bool valid = contextItem->isValid(key);
+ bool valid = contextItem->isValidData(key);
delete contextItem;
IF_FAIL_RETURN_TAG(valid, E_INV_RULE, _E, "Invalid parameter");
IF_FAIL_RETURN(!__is_member_key(entry, key), E_INV_RULE);
IF_FAIL_RETURN(entry->category == CATEGORY_CONDITION, E_INV_RULE);
ConditionItem contextItem(entry->type);
- IF_FAIL_RETURN(contextItem.isValid(key), E_INV_RULE);
+ IF_FAIL_RETURN(contextItem.isValidData(key), E_INV_RULE);
IF_FAIL_RETURN(__is_member_key(entry, key), E_NO_DATA);
ctx_sched_job_context_prepare_attribute_str(entry->jobContext, key);
ContextItem* contextItem = __get_context_item(entry);
IF_FAIL_RETURN(contextItem, E_FAILED);
- bool valid = contextItem->isValid(key, value);
+ bool valid = contextItem->isValidData(key, value);
delete contextItem;
IF_FAIL_RETURN_TAG(valid, E_INV_RULE, _E, "Invalid parameter");
IF_FAIL_RETURN(__is_member_key(entry, key), E_NO_DATA);
ContextItem* contextItem = __get_context_item(entry);
IF_FAIL_RETURN(contextItem, E_FAILED);
- bool valid = contextItem->isValid(key, value);
+ bool valid = contextItem->isValidData(key, value);
delete contextItem;
IF_FAIL_RETURN_TAG(valid, E_INV_RULE, _E, "Invalid parameter");
IF_FAIL_RETURN(__is_member_key(entry, key), E_NO_DATA);