package btools.routingapp; import android.app.Service; import android.content.Intent; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Base64; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.zip.GZIPOutputStream; import btools.router.OsmNodeNamed; import btools.router.RoutingEngine; public class BRouterService extends Service { @Override public IBinder onBind(Intent arg0) { return myBRouterServiceStub; } private IBRouterService.Stub myBRouterServiceStub = new IBRouterService.Stub() { @Override public String getTrackFromParams(Bundle params) throws RemoteException { logBundle(params); BRouterWorker worker = new BRouterWorker(); for (String key : params.keySet()) { // Log.d("BS", "income " + key + " = " + params.get(key)); } int engineMode = 0; if (params.containsKey("engineMode")) { engineMode = params.getInt("engineMode", 0); } // get base dir from private file String baseDir = null; InputStream configInput = null; try { configInput = openFileInput("config15.dat"); BufferedReader br = new BufferedReader(new InputStreamReader(configInput)); baseDir = br.readLine(); } catch (Exception e) { } finally { if (configInput != null) try { configInput.close(); } catch (Exception ee) { } } worker.baseDir = baseDir; worker.segmentDir = new File(baseDir, "brouter/segments4"); String errMsg = null; if (engineMode == RoutingEngine.BROUTER_ENGINEMODE_ROUTING) { String remoteProfile = params.getString("remoteProfile", null); if (remoteProfile == null) { remoteProfile = checkForTestDummy(baseDir); } if (remoteProfile != null) { errMsg = getConfigForRemoteProfile(worker, baseDir, remoteProfile); } else if (params.containsKey("profile")) { String profile = params.getString("profile"); worker.profileName = profile; worker.profilePath = baseDir + "/brouter/profiles2/" + profile + ".brf"; worker.rawTrackPath = baseDir + "/brouter/modes/" + profile + "_rawtrack.dat"; if (!new File(worker.profilePath).exists()) { errMsg = "Profile " + profile + " does not exists"; } else { try { readNogos(worker, baseDir); } catch (Exception e) { errMsg = e.getLocalizedMessage(); } } } else { errMsg = getConfigFromMode(worker, baseDir, params.getString("v"), params.getString("fast")); } } else { worker.profilePath = baseDir + "/brouter/profiles2/dummy.brf"; } if (errMsg != null) { return errMsg; } boolean canCompress = "true".equals(params.getString("acceptCompressedResult")); try { String gpxMessage = worker.getTrackFromParams(params); if (canCompress && gpxMessage.startsWith("<")) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write("z64".getBytes(Charset.forName("UTF-8"))); // marker prefix OutputStream os = new GZIPOutputStream(baos); byte[] ab = gpxMessage.getBytes(Charset.forName("UTF-8")); // StandardCharsets.UTF_8 gpxMessage = null; os.write(ab); ab = null; os.close(); gpxMessage = Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT); return gpxMessage; } catch (Exception e) { return "error compressing result"; } } return gpxMessage; } catch (IllegalArgumentException iae) { return iae.getMessage(); } } private String getConfigFromMode(BRouterWorker worker, String baseDir, String mode, String fast) { boolean isFast = "1".equals(fast) || "true".equals(fast) || "yes".equals(fast); String mode_key = mode + "_" + (isFast ? "fast" : "short"); BufferedReader br = null; try { String modesFile = baseDir + "/brouter/modes/serviceconfig.dat"; br = new BufferedReader(new FileReader(modesFile)); for (; ; ) { String line = br.readLine(); if (line == null) break; ServiceModeConfig smc = new ServiceModeConfig(line); if (!smc.mode.equals(mode_key)) continue; worker.profileName = smc.profile; worker.profileParams = (smc.params.equals("noparams") ? null : smc.params); worker.profilePath = baseDir + "/brouter/profiles2/" + smc.profile + ".brf"; worker.rawTrackPath = baseDir + "/brouter/modes/" + mode_key + "_rawtrack.dat"; readNogos(worker, baseDir); // veto nogos by profiles veto list List nogoList = new ArrayList<>(worker.nogoList); worker.nogoList.clear(); for (OsmNodeNamed nogo : nogoList) { if (!smc.nogoVetos.contains(nogo.ilon + "," + nogo.ilat)) { worker.nogoList.add(nogo); } } List nogoPolygonsList = new ArrayList<>(worker.nogoPolygonsList); worker.nogoPolygonsList.clear(); for (OsmNodeNamed nogo : nogoPolygonsList) { if (!smc.nogoVetos.contains(nogo.ilon + "," + nogo.ilat)) { worker.nogoPolygonsList.add(nogo); } } return null; } } catch (Exception e) { return "no brouter service config found, mode " + mode_key; } finally { if (br != null) try { br.close(); } catch (Exception ee) { } } return "no brouter service config found for mode " + mode_key; } private String getConfigForRemoteProfile(BRouterWorker worker, String baseDir, String remoteProfile) { worker.profileName = "remote"; worker.profilePath = baseDir + "/brouter/profiles2/remote.brf"; worker.rawTrackPath = baseDir + "/brouter/modes/remote_rawtrack.dat"; // store profile only if not identical (to preserve timestamp) byte[] profileBytes = remoteProfile.getBytes(); File profileFile = new File(worker.profilePath); try { readNogos(worker, baseDir); if (!fileEqual(profileBytes, profileFile)) { OutputStream os = null; try { os = new FileOutputStream(profileFile); os.write(profileBytes); } finally { if (os != null) try { os.close(); } catch (IOException io) { } } } } catch (Exception e) { return "error caching remote profile: " + e; } return null; } private void readNogos(BRouterWorker worker, String baseDir) throws Exception { // add nogos from waypoint database CoordinateReader cor = CoordinateReader.obtainValidReader(baseDir, true); worker.nogoList = new ArrayList(cor.nogopoints); worker.nogoPolygonsList = new ArrayList(); } private boolean fileEqual(byte[] fileBytes, File file) throws Exception { if (!file.exists()) { return false; } int nbytes = fileBytes.length; int pos = 0; int blen = 8192; byte[] buf = new byte[blen]; InputStream is = null; try { is = new FileInputStream(file); while (pos < nbytes) { int len = is.read(buf, 0, blen); if (len <= 0) return false; if (pos + len > nbytes) return false; for (int j = 0; j < len; j++) { if (fileBytes[pos++] != buf[j]) { return false; } } } return true; } finally { if (is != null) try { is.close(); } catch (IOException io) { } } } private String checkForTestDummy(String baseDir) { File testdummy = new File(baseDir + "/brouter/profiles2/remotetestdummy.brf"); if (!testdummy.exists()) return null; BufferedReader br = null; StringBuilder sb = new StringBuilder(); try { br = new BufferedReader(new FileReader(testdummy)); for (; ; ) { String line = br.readLine(); if (line == null) break; sb.append(line).append('\n'); } return sb.toString(); } catch (Exception e) { throw new RuntimeException("error reading " + testdummy); } finally { if (br != null) try { br.close(); } catch (Exception ee) { } } } private void logBundle(Bundle params) { if (AppLogger.isLogging()) { for (String k : params.keySet()) { Object val = "remoteProfile".equals(k) ? "<..cut..>" : params.getString(k); String desc = "key=" + k + (val == null ? "" : " class=" + val.getClass() + " val=" + val.toString()); AppLogger.log(desc); } } } }; @Override public void onCreate() { super.onCreate(); } @Override public void onDestroy() { super.onDestroy(); } // This is the old onStart method that will be called on the pre-2.0 // platform. On 2.0 or later we override onStartCommand() so this // method will not be called. @Override @SuppressWarnings("deprecation") public void onStart(Intent intent, int startId) { handleStart(intent, startId); } @Override public int onStartCommand(Intent intent, int flags, int startId) { handleStart(intent, startId); return START_STICKY; } void handleStart(Intent intent, int startId) { } }