traffic_traff_android.c (navit-0.5.5) | : | traffic_traff_android.c (navit-0.5.6) | ||
---|---|---|---|---|
skipping to change at line 25 | skipping to change at line 25 | |||
* along with this program; if not, write to the | * along with this program; if not, write to the | |||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |||
* Boston, MA 02110-1301, USA. | * Boston, MA 02110-1301, USA. | |||
*/ | */ | |||
/** | /** | |||
* @file traffic_traff_android.c | * @file traffic_traff_android.c | |||
* | * | |||
* @brief The TraFF plugin for Android | * @brief The TraFF plugin for Android | |||
* | * | |||
* This plugin receives TraFF feeds via Android broadcasts. | * This plugin receives TraFF feeds via Android broadcasts and content providers . | |||
*/ | */ | |||
#include <string.h> | #include <string.h> | |||
#include <time.h> | #include <time.h> | |||
#ifdef _POSIX_C_SOURCE | #ifdef _POSIX_C_SOURCE | |||
#include <sys/types.h> | #include <sys/types.h> | |||
#endif | #endif | |||
#include "glib_slice.h" | #include "glib_slice.h" | |||
#include "config.h" | #include "config.h" | |||
#include "item.h" | #include "item.h" | |||
#include "attr.h" | #include "attr.h" | |||
#include "coord.h" | #include "coord.h" | |||
#include "map.h" | ||||
#include "route_protected.h" | ||||
#include "route.h" | ||||
#include "transform.h" | ||||
#include "xmlconfig.h" | #include "xmlconfig.h" | |||
#include "android.h" | #include "android.h" | |||
#include "traffic.h" | #include "traffic.h" | |||
#include "plugin.h" | #include "plugin.h" | |||
#include "callback.h" | #include "callback.h" | |||
#include "vehicle.h" | ||||
#include "debug.h" | #include "debug.h" | |||
#include "navit.h" | #include "navit.h" | |||
#include "util.h" | ||||
/** | ||||
* @brief Minimum area around the current position for which to retrieve traffic | ||||
updates. | ||||
* | ||||
* 100000 is equivalent to around 50 km on each side of the current position. Th | ||||
e actual subscription area | ||||
* can be larger, allowing for a subscription area to be kept over multiple posi | ||||
tion updates. | ||||
* | ||||
* The actual subscription area around the current location is stored in | ||||
* {@link struct traffic_priv::position_rect} and updated in | ||||
* {@link traffic_traff_android_position_callback(struct traffic_priv *, struct | ||||
navit *, struct vehicle *)}. | ||||
*/ | ||||
#define POSITION_RECT_SIZE 100000 | ||||
/** | /** | |||
* @brief Stores information about the plugin instance. | * @brief Stores information about the plugin instance. | |||
*/ | */ | |||
struct traffic_priv { | struct traffic_priv { | |||
struct navit * nav; /**< The navit instance */ | struct navit * nav; /**< The navit instance */ | |||
struct callback * cbid; /**< The callback function for TraFF feeds **/ | struct callback * cbid; /**< The callback function for TraFF feeds **/ | |||
int position_valid; /**< Whether Navit currently has a valid positio | ||||
n */ | ||||
struct coord_rect * position_rect; /**< Rectangle around last known vehicle | ||||
position (in `projection_mg`) */ | ||||
struct map_selection * route_map_sel; /**< Map selection for the current rou | ||||
te */ | ||||
jclass NavitTraffClass; /**< The `NavitTraff` class */ | jclass NavitTraffClass; /**< The `NavitTraff` class */ | |||
jobject NavitTraff; /**< An instance of `NavitTraff` */ | jobject NavitTraff; /**< An instance of `NavitTraff` */ | |||
}; | }; | |||
void traffic_traff_android_destroy(struct traffic_priv * this_); | ||||
struct traffic_message ** traffic_traff_android_get_messages(struct traffic_priv * this_); | struct traffic_message ** traffic_traff_android_get_messages(struct traffic_priv * this_); | |||
/** | /** | |||
* @brief Destructor. | ||||
*/ | ||||
void traffic_traff_android_destroy(struct traffic_priv * this_) { | ||||
jmethodID cid; | ||||
cid = (*jnienv)->GetMethodID(jnienv, this_->NavitTraffClass, "close", "()V") | ||||
; | ||||
if (cid == NULL) { | ||||
dbg(lvl_error,"no method found"); | ||||
return; /* exception thrown */ | ||||
} | ||||
(*jnienv)->CallVoidMethod(jnienv, this_->NavitTraff, cid); | ||||
if (this_->position_rect) | ||||
g_free(this_->position_rect); | ||||
this_->position_rect = NULL; | ||||
if (this_->route_map_sel) | ||||
route_free_selection(this_->route_map_sel); | ||||
this_->route_map_sel = NULL; | ||||
} | ||||
/** | ||||
* @brief Returns an empty traffic report. | * @brief Returns an empty traffic report. | |||
* | * | |||
* @return Always `NULL` | * @return Always `NULL` | |||
*/ | */ | |||
struct traffic_message ** traffic_traff_android_get_messages(struct traffic_priv * this_) { | struct traffic_message ** traffic_traff_android_get_messages(struct traffic_priv * this_) { | |||
return NULL; | return NULL; | |||
} | } | |||
/** | /** | |||
* @brief The methods implemented by this plugin | * @brief The methods implemented by this plugin | |||
*/ | */ | |||
static struct traffic_methods traffic_traff_android_meth = { | static struct traffic_methods traffic_traff_android_meth = { | |||
traffic_traff_android_get_messages, | traffic_traff_android_get_messages, | |||
traffic_traff_android_destroy, | ||||
}; | }; | |||
/** | /** | |||
* @brief Called when a new TraFF feed is received. | * @brief Called when a new TraFF feed is received. | |||
* | * | |||
* @param this_ Private data for the module instance | * @param this_ Private data for the module instance | |||
* @param feed Feed data in string form | * @param feed Feed data in string form | |||
*/ | */ | |||
static void traffic_traff_android_on_feed_received(struct traffic_priv * this_, char * feed) { | static void traffic_traff_android_on_feed_received(struct traffic_priv * this_, char * feed) { | |||
struct attr * attr; | struct attr * attr; | |||
skipping to change at line 110 | skipping to change at line 154 | |||
dbg(lvl_debug, "processing traffic feed:\n%s", feed); | dbg(lvl_debug, "processing traffic feed:\n%s", feed); | |||
messages = traffic_get_messages_from_xml_string(traffic, feed); | messages = traffic_get_messages_from_xml_string(traffic, feed); | |||
if (messages) { | if (messages) { | |||
dbg(lvl_debug, "got messages from feed, processing"); | dbg(lvl_debug, "got messages from feed, processing"); | |||
traffic_process_messages(traffic, messages); | traffic_process_messages(traffic, messages); | |||
g_free(messages); | g_free(messages); | |||
} | } | |||
} | } | |||
/** | /** | |||
* @brief Sets the route map selection | ||||
* | ||||
* @param this_ The instance which will handle the selection update | ||||
*/ | ||||
static void traffic_traff_android_set_selection(struct traffic_priv * this_) { | ||||
struct route * route; | ||||
struct coord_geo lu, rl; | ||||
gchar *filter_list; | ||||
jstring j_filter_list; | ||||
gchar *min_road_class; | ||||
jmethodID cid; | ||||
if (this_->route_map_sel) | ||||
route_free_selection(this_->route_map_sel); | ||||
this_->route_map_sel = NULL; | ||||
if (navit_get_destination_count(this_->nav) && (route = (navit_get_route(thi | ||||
s_->nav)))) | ||||
this_->route_map_sel = route_get_selection(route); | ||||
/* start building the filter list */ | ||||
filter_list = g_strconcat_printf(NULL, "<filter_list>\n"); | ||||
if (this_->position_rect) { | ||||
transform_to_geo(projection_mg, &this_->position_rect->lu, &lu); | ||||
transform_to_geo(projection_mg, &this_->position_rect->rl, &rl); | ||||
filter_list = g_strconcat_printf(filter_list, " <filter bbox=\"%.5f % | ||||
.5f %.5f %.5f\"/>\n", | ||||
rl.lat, lu.lng, lu.lat, rl.lng); | ||||
} | ||||
for (struct map_selection * sel = this_->route_map_sel; sel; sel = sel->next | ||||
) { | ||||
transform_to_geo(projection_mg, &sel->u.c_rect.lu, &lu); | ||||
transform_to_geo(projection_mg, &sel->u.c_rect.rl, &rl); | ||||
min_road_class = order_to_min_road_class(sel->order); | ||||
if (!min_road_class) | ||||
filter_list = g_strconcat_printf(filter_list, " <filter bbox=\"%. | ||||
5f %.5f %.5f %.5f\"/>\n", | ||||
rl.lat, lu.lng, lu.lat, rl.lng); | ||||
else | ||||
filter_list = g_strconcat_printf(filter_list, " <filter min_road_ | ||||
class=\"%s\" bbox=\"%.5f %.5f %.5f %.5f\"/>\n", | ||||
min_road_class, rl.lat, lu.lng, lu. | ||||
lat, rl.lng); | ||||
} | ||||
/* the trailing \0 is required for NewStringUTF */ | ||||
filter_list = g_strconcat_printf(filter_list, "</filter_list>\0"); | ||||
j_filter_list = (*jnienv)->NewStringUTF(jnienv, filter_list); | ||||
cid = (*jnienv)->GetMethodID(jnienv, this_->NavitTraffClass, "onFilterUpdate | ||||
", "(Ljava/lang/String;)V"); | ||||
if (cid) | ||||
(*jnienv)->CallVoidMethod(jnienv, this_->NavitTraff, cid, j_filter_list) | ||||
; | ||||
g_free(filter_list); | ||||
} | ||||
/** | ||||
* @brief Callback for destination changes | ||||
* | ||||
* @param this_ The instance which will handle the destination update | ||||
*/ | ||||
static void traffic_traff_android_destination_callback(struct traffic_priv * thi | ||||
s_) { | ||||
traffic_traff_android_set_selection(this_); | ||||
} | ||||
/** | ||||
* @brief Callback for navigation status changes | ||||
* | ||||
* This callback is necessary to force an update of existing subscriptions when | ||||
Navit acquires a new | ||||
* position (after not having had valid position information), as the map select | ||||
ion will change when | ||||
* the current position becomes known for the first time. | ||||
* | ||||
* @param this_ The instance which will handle the navigation status update | ||||
* @param status The status of the navigation engine (the value of the {@code na | ||||
v_status} attribute) | ||||
*/ | ||||
static void traffic_traff_android_status_callback(struct traffic_priv * this_, i | ||||
nt status) { | ||||
int new_position_valid = (status != 1); | ||||
if (new_position_valid && !this_->position_valid) { | ||||
this_->position_valid = new_position_valid; | ||||
traffic_traff_android_set_selection(this_); | ||||
} else if (new_position_valid != this_->position_valid) | ||||
this_->position_valid = new_position_valid; | ||||
} | ||||
/** | ||||
* @brief Callback for position changes | ||||
* | ||||
* This updates {@link struct traffic_priv::position_rect} if the vehicle has mo | ||||
ved far enough from its | ||||
* center to be within {@link POSITION_RECT_SIZE} of one of its boundaries. The | ||||
new rectangle is created | ||||
* with twice that amount of padding, allowing the vehicle to move for at least | ||||
that distance before the | ||||
* subscription needs to be updated again. | ||||
* | ||||
* @param this_ The instance which will handle the position update | ||||
* @param navit The Navit instance | ||||
* @param vehicle The vehicle which delivered the position update and from which | ||||
the position can be queried | ||||
*/ | ||||
static void traffic_traff_android_position_callback(struct traffic_priv * this_, | ||||
struct navit *navit, | ||||
struct vehicle *vehicle) { | ||||
struct attr attr; | ||||
struct coord c; | ||||
struct coord_rect cr; | ||||
jmethodID cid; | ||||
if (!vehicle_get_attr(vehicle, attr_position_coord_geo, &attr, NULL)) | ||||
return; | ||||
transform_from_geo(projection_mg, attr.u.coord_geo, &c); | ||||
cr.lu = c; | ||||
cr.rl = c; | ||||
cr.lu.x -= POSITION_RECT_SIZE; | ||||
cr.rl.x += POSITION_RECT_SIZE; | ||||
cr.lu.y += POSITION_RECT_SIZE; | ||||
cr.rl.y -= POSITION_RECT_SIZE; | ||||
if (!this_->position_rect) | ||||
this_->position_rect = g_new0(struct coord_rect, 1); | ||||
if (!coord_rect_contains(this_->position_rect, &cr.lu) || !coord_rect_contai | ||||
ns(this_->position_rect, &cr.rl)) { | ||||
cr.lu.x -= POSITION_RECT_SIZE; | ||||
cr.rl.x += POSITION_RECT_SIZE; | ||||
cr.lu.y += POSITION_RECT_SIZE; | ||||
cr.rl.y -= POSITION_RECT_SIZE; | ||||
*(this_->position_rect) = cr; | ||||
traffic_traff_android_set_selection(this_); | ||||
} | ||||
} | ||||
/** | ||||
* @brief Initializes a traff_android plugin | * @brief Initializes a traff_android plugin | |||
* | * | |||
* @return True on success, false on failure | * @return True on success, false on failure | |||
*/ | */ | |||
static int traffic_traff_android_init(struct traffic_priv * this_) { | static int traffic_traff_android_init(struct traffic_priv * this_) { | |||
jmethodID cid; | jmethodID cid; | |||
struct route * route; | ||||
struct attr attr; | ||||
struct navigation * navigation; | ||||
if (!android_find_class_global("org/navitproject/navit/NavitTraff", &this_-> NavitTraffClass)) | if (!android_find_class_global("org/navitproject/navit/NavitTraff", &this_-> NavitTraffClass)) | |||
return 0; | return 0; | |||
cid = (*jnienv)->GetMethodID(jnienv, this_->NavitTraffClass, "<init>", "(Lan droid/content/Context;J)V"); | cid = (*jnienv)->GetMethodID(jnienv, this_->NavitTraffClass, "<init>", "(Lan droid/content/Context;J)V"); | |||
if (cid == NULL) { | if (cid == NULL) { | |||
dbg(lvl_error,"no method found"); | dbg(lvl_error,"no method found"); | |||
return 0; /* exception thrown */ | return 0; /* exception thrown */ | |||
} | } | |||
this_->NavitTraff=(*jnienv)->NewObject(jnienv, this_->NavitTraffClass, cid, android_activity, | this_->NavitTraff=(*jnienv)->NewObject(jnienv, this_->NavitTraffClass, cid, android_activity, | |||
(jlong) this_->cbid); | (jlong) this_->cbid); | |||
dbg(lvl_debug,"result=%p", this_->NavitTraff); | dbg(lvl_debug,"result=%p", this_->NavitTraff); | |||
if (!this_->NavitTraff) | if (!this_->NavitTraff) | |||
return 0; | return 0; | |||
if (this_->NavitTraff) | if (this_->NavitTraff) | |||
this_->NavitTraff = (*jnienv)->NewGlobalRef(jnienv, this_->NavitTraff); | this_->NavitTraff = (*jnienv)->NewGlobalRef(jnienv, this_->NavitTraff); | |||
/* register callbacks for position and destination changes */ | ||||
navit_add_callback(this_->nav, callback_new_attr_1(callback_cast(traffic_tra | ||||
ff_android_position_callback), | ||||
attr_position_coord_geo, this_)); | ||||
navit_add_callback(this_->nav, callback_new_attr_1(callback_cast(traffic_tra | ||||
ff_android_destination_callback), | ||||
attr_destination, this_)); | ||||
if ((navigation = navit_get_navigation(this_->nav))) | ||||
navigation_register_callback(navigation, attr_nav_status, | ||||
callback_new_attr_1(callback_cast(traffic_t | ||||
raff_android_status_callback), attr_nav_status, this_)); | ||||
return 1; | return 1; | |||
} | } | |||
/** | /** | |||
* @brief Registers a new traff_android traffic plugin | * @brief Registers a new traff_android traffic plugin | |||
* | * | |||
* @param nav The navit instance | * @param nav The navit instance | |||
* @param meth Receives the traffic methods | * @param meth Receives the traffic methods | |||
* @param attrs The attributes for the map | * @param attrs The attributes for the map | |||
* @param cbl | * @param cbl | |||
skipping to change at line 154 | skipping to change at line 324 | |||
*/ | */ | |||
static struct traffic_priv * traffic_traff_android_new(struct navit *nav, struct traffic_methods *meth, | static struct traffic_priv * traffic_traff_android_new(struct navit *nav, struct traffic_methods *meth, | |||
struct attr **attrs, struct callback_list *cbl) { | struct attr **attrs, struct callback_list *cbl) { | |||
struct traffic_priv *ret; | struct traffic_priv *ret; | |||
dbg(lvl_debug, "enter"); | dbg(lvl_debug, "enter"); | |||
ret = g_new0(struct traffic_priv, 1); | ret = g_new0(struct traffic_priv, 1); | |||
ret->nav = nav; | ret->nav = nav; | |||
ret->cbid = callback_new_1(callback_cast(traffic_traff_android_on_feed_recei ved), ret); | ret->cbid = callback_new_1(callback_cast(traffic_traff_android_on_feed_recei ved), ret); | |||
ret->position_valid = 0; | ||||
ret->position_rect = NULL; | ||||
ret->route_map_sel = NULL; | ||||
/* TODO populate members, if any */ | /* TODO populate members, if any */ | |||
*meth = traffic_traff_android_meth; | *meth = traffic_traff_android_meth; | |||
traffic_traff_android_init(ret); | traffic_traff_android_init(ret); | |||
return ret; | return ret; | |||
} | } | |||
/** | /** | |||
* @brief Initializes the traffic plugin. | * @brief Initializes the traffic plugin. | |||
End of changes. 12 change blocks. | ||||
1 lines changed or deleted | 204 lines changed or added |