Open barbeau opened 10 years ago
Starting point for NDK interface, from an early version of the the Bliksem Technology Preview app:
bliksem.c
#include <jni.h>
#include <string.h>
#include <android/log.h>
#include "config.h"
#include "rrrr.h"
#include "transitdata.h"
#include "router.h"
#include <syslog.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/stat.h>
#define DEBUG_TAG "NDK_libbliksem"
static transit_data_t tdata;
static char *stops = NULL;
static size_t stops_len = 0;
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
transit_data_load(RRRR_INPUT_FILE, &tdata);
int fd = open("stops.dat", O_RDONLY, 0 );
struct stat statbuf;
fstat (fd, &statbuf);
stops_len = statbuf.st_size;
stops = (char *) mmap(NULL, stops_len, PROT_READ, MAP_SHARED, fd, 0);
return JNI_VERSION_1_6;
}
jint JNI_OnUnLoad(JavaVM* vm, void* reserved)
{
transit_data_close(&tdata);
if (stops != NULL)
munmap(stops, stops_len);
return JNI_VERSION_1_6;
}
jstring Java_nl_ovapi_bliksem_PlanFragment_geocode(JNIEnv * env, jobject this, jstring param1)
{
char *query = (*env)->GetStringUTFChars(env, param1, NULL);
char result_buf[1024];
size_t offset = 0;
char *result = stops;
while (result != NULL && offset < 768 ) {
result = strcasestr(result, query);
if (result != NULL) {
char *src = result;
size_t length;
while (src > stops && src[-1] != '\n') {
src--;
}
while (result[0] != '\n') {
result++;
}
result++;
length = result - src;
strncpy(&result_buf[offset], src, length);
offset += length;
}
}
result_buf[offset] = '\0';
jstring result = (*env)->NewStringUTF(env, result_buf);
return result;
}
jstring Java_nl_ovapi_bliksem_PlanFragment_planRoute(JNIEnv * env, jobject this, jint from, jint to, jint time)
{
char result_buf[4096];
router_t router;
router_setup(&router, &tdata);
router_request_t req;
req.from=from;
req.to=to;
req.time=time;
req.walk_speed=0.5;
router_route(&router, &req);
int result_length = router_result_dump(&router, &req, result_buf, 4096);
jstring result = (*env)->NewStringUTF(env, result_buf);
router_teardown(&router);
return result;
}
Details on the current demo Bliksem Technology Preview app app from Thomas Koch:
The current Android application uses the tabular/csv and inside Java it de-serializes that String to java objects. It is very easy to switch that tabular output to OTP-JSON however, it would just be a matter of calling the method as currrently done in worker.c You can see below how the current library used by the Android client looks like. Linking it to the java is as easy as adding
private native String planRoute(int from, int to,boolean arriveby,long time,boolean bus,boolean train,boolean tram,boolean ferry,boolean subway, double speed, int extrasec);
to the Activity/Fragment and loading the library. In the future that should be replaced by a easier-to-implement abstraction that preferably sends out Java objects instead of JSON strings.
#include <jni.h>
#include <string.h>
#include <android/log.h>
#include "config.h"
#include "rrrr.h"
#include <syslog.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <getopt.h>
#include <time.h>
#include "tdata.h"
#include "router.h"
#include <syslog.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/stat.h>
#define DEBUG_TAG "NDK_libbliksem"
static tdata_t tdata;
static char *stops = NULL;
static size_t stops_len = 0;
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
tdata_load(RRRR_INPUT_FILE, &tdata);
return JNI_VERSION_1_6;
}
jint JNI_OnUnLoad(JavaVM* vm, void* reserved)
{
tdata_close(&tdata);
return JNI_VERSION_1_6;
}
jlong Java_nl_ovapi_bliksem_PlanFragment_planRoute(JNIEnv * env, jobject this, jint from, jint to, jboolean arriveby,jlong epoch,jboolean bus,jboolean train,jboolean tram,jboolean ferry,jboolean subway, jdouble speed, jint walkslack)
{
char result_buf[8000] = "test";
char *iso_datetime = NULL;
router_request_t req;
router_request_initialize(&req);
req.from=from;
req.to=to;
req.walk_speed = speed;
req.arrive_by=arriveby;
req.walk_slack = walkslack;
router_request_from_epoch (&req, &tdata, epoch); // from struct_tm instead?
req.mode = 0;
if (tram){
req.mode |= m_tram;
}
if (subway){
req.mode |= m_subway;
}
if (train){
req.mode |= m_rail;
}
if (bus){
req.mode |= m_bus;
}
if (ferry){
req.mode |= m_ferry;
}
router_t router;
router_setup(&router, &tdata);
router_route(&router, &req);
uint32_t n_reversals = req.arrive_by ? 1 : 2;
for (uint32_t i = 0; i < n_reversals; ++i) {
router_request_reverse (&router, &req); // handle case where route is not reversed
router_route (&router, &req);
}
int result_length = router_result_dump(&router, &req, result_buf, 8000);
jstring result = (*env)->NewStringUTF(env, result_buf);
router_teardown(&router);
return result;
}
jlong Java_nl_ovapi_bliksem_PlanFragment_getStartTime(JNIEnv * env, jobject this)
{
return (jlong) tdata.calendar_start_time;
}
See also https://github.com/leshka890/rrrr-android.
Looks like this is basically a hello world to get RRRR running on Android, as it doesn't have any UI:
I hit an issue trying to get it to run: https://github.com/leshka890/rrrr-android/issues/2
It's also unclear what the current license is for this project - I've opened a ticket here asking: https://github.com/leshka890/rrrr-android/issues/1
If it's Apache v2.0, we could use some of this code to get started with RRRR in OTP Android.
License is Apache v2, so we can use the project in OTP Android.
Turns out the above issue really isn't an issue, just part of the JSON response from RRRR. So, looks like rrrr-android is working as intended.
See https://groups.google.com/forum/#!topic/opentripplanner-dev/KsZGE7B-CVQ.
Routing engine code here: https://github.com/bliksemlabs/rrrr
Would require the Android NDK: http://developer.android.com/tools/sdk/ndk/index.html