I'm trying to get the directions from the user's current location to a user defined location in the app that I'm building. This seems like it should be a relatively easy thing to do but I'm getting stuck on which API to use.
Right now I've managed to hook up to the google directions API but the JSON it's returning is very strange (they've added a \n everywhere to make it human readable) which suggests to me that this API isn't the correct one for mobile.
I've also seen the google places API being recommended for this purpose but I can't seem to find out how to use it from the documentation.
Any help is greatly appreciated since I'm just a titch confused
EDIT: Just to clarify the questions is which API I should be using to get directions for maps?
I do not remember where I get it but this classes help me a lot, it includes if you want to draw the route.
GoogleParser.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.google.android.maps.GeoPoint;
import com.monumentos.log.Logger;
public class GoogleParser extends XMLParser implements Parser {
/** Distance covered. **/
private int distance;
public GoogleParser(String feedUrl) {
super(feedUrl);
}
/**
* Parses a url pointing to a Google JSON object to a Route object.
* #return a Route object based on the JSON object.
*/
public Route parse() {
// turn the stream into a string
final String result = convertStreamToString(this.getInputStream());
//Create an empty route
final Route route = new Route();
//Create an empty segment
final Segment segment = new Segment();
try {
//Tranform the string into a json object
final JSONObject json = new JSONObject(result);
//Get the route object
final JSONObject jsonRoute = json.getJSONArray("routes").getJSONObject(0);
//Get the leg, only one leg as we don't support waypoints
final JSONObject leg = jsonRoute.getJSONArray("legs").getJSONObject(0);
//Get the steps for this leg
final JSONArray steps = leg.getJSONArray("steps");
//Number of steps for use in for loop
final int numSteps = steps.length();
//Set the name of this route using the start & end addresses
route.setName(leg.getString("start_address") + " to " + leg.getString("end_address"));
//Get google's copyright notice (tos requirement)
route.setCopyright(jsonRoute.getString("copyrights"));
//Get the total length of the route.
route.setLength(leg.getJSONObject("distance").getInt("value"));
//Get any warnings provided (tos requirement)
if (!jsonRoute.getJSONArray("warnings").isNull(0)) {
route.setWarning(jsonRoute.getJSONArray("warnings").getString(0));
}
/* Loop through the steps, creating a segment for each one and
* decoding any polylines found as we go to add to the route object's
* map array. Using an explicit for loop because it is faster!
*/
for (int i = 0; i < numSteps; i++) {
//Get the individual step
final JSONObject step = steps.getJSONObject(i);
//Get the start position for this step and set it on the segment
final JSONObject start = step.getJSONObject("start_location");
final GeoPoint position = new GeoPoint((int) (start.getDouble("lat")*1E6),
(int) (start.getDouble("lng")*1E6));
segment.setPoint(position);
//Set the length of this segment in metres
final int length = step.getJSONObject("distance").getInt("value");
distance += length;
segment.setLength(length);
segment.setDistance(distance/1000);
//Strip html from google directions and set as turn instruction
segment.setInstruction(step.getString("html_instructions").replaceAll("<(.*?)*>", ""));
//Retrieve & decode this segment's polyline and add it to the route.
route.addPoints(decodePolyLine(step.getJSONObject("polyline").getString("points")));
//Push a copy of the segment to the route
route.addSegment(segment.copy());
}
} catch (JSONException e) {
Logger.appendLog( "Google JSON Parser - " + feedUrl);
}
return route;
}
/**
* Convert an inputstream to a string.
* #param input inputstream to convert.
* #return a String of the inputstream.
*/
private static String convertStreamToString(final InputStream input) {
final BufferedReader reader = new BufferedReader(new InputStreamReader(input));
final StringBuilder sBuf = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sBuf.append(line);
}
} catch (IOException e) {
Logger.appendLog( "Google parser, stream2string");
} finally {
try {
input.close();
} catch (IOException e) {
Logger.appendLog( "Google parser, stream2string");
}
}
return sBuf.toString();
}
/**
* Decode a polyline string into a list of GeoPoints.
* #param poly polyline encoded string to decode.
* #return the list of GeoPoints represented by this polystring.
*/
private List<GeoPoint> decodePolyLine(final String poly) {
int len = poly.length();
int index = 0;
List<GeoPoint> decoded = new ArrayList<GeoPoint>();
int lat = 0;
int lng = 0;
while (index < len) {
int b;
int shift = 0;
int result = 0;
do {
b = poly.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = poly.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lng += dlng;
decoded.add(new GeoPoint(
(int) (lat*1E6 / 1E5), (int) (lng*1E6 / 1E5)));
}
return decoded;
}
}
Parser.java
public interface Parser {
public Route parse();
}
Route.java
import java.util.ArrayList;
import java.util.List;
import com.google.android.maps.GeoPoint;
public class Route {
private String name;
private final List<GeoPoint> points;
private List<Segment> segments;
private String copyright;
private String warning;
private String country;
private int length;
private String polyline;
public Route() {
points = new ArrayList<GeoPoint>();
segments = new ArrayList<Segment>();
}
public void addPoint(final GeoPoint p) {
points.add(p);
}
public void addPoints(final List<GeoPoint> points) {
this.points.addAll(points);
}
public List<GeoPoint> getPoints() {
return points;
}
public void addSegment(final Segment s) {
segments.add(s);
}
public List<Segment> getSegments() {
return segments;
}
/**
* #param name the name to set
*/
public void setName(final String name) {
this.name = name;
}
/**
* #return the name
*/
public String getName() {
return name;
}
/**
* #param copyright the copyright to set
*/
public void setCopyright(String copyright) {
this.copyright = copyright;
}
/**
* #return the copyright
*/
public String getCopyright() {
return copyright;
}
/**
* #param warning the warning to set
*/
public void setWarning(String warning) {
this.warning = warning;
}
/**
* #return the warning
*/
public String getWarning() {
return warning;
}
/**
* #param country the country to set
*/
public void setCountry(String country) {
this.country = country;
}
/**
* #return the country
*/
public String getCountry() {
return country;
}
/**
* #param length the length to set
*/
public void setLength(int length) {
this.length = length;
}
/**
* #return the length
*/
public int getLength() {
return length;
}
/**
* #param polyline the polyline to set
*/
public void setPolyline(String polyline) {
this.polyline = polyline;
}
/**
* #return the polyline
*/
public String getPolyline() {
return polyline;
}
}
RouteOverlay.java
public class RouteOverlay extends Overlay {
/** GeoPoints representing this routePoints. **/
private final List<GeoPoint> routePoints;
/** Colour to paint routePoints. **/
private int colour;
/** Alpha setting for route overlay. **/
private static final int ALPHA = 200;
/** Stroke width. **/
private static final float STROKE = 4.5f;
/** Route path. **/
private final Path path;
/** Point to draw with. **/
private final Point p;
/** Paint for path. **/
private final Paint paint;
/**
* Public constructor.
*
* #param route Route object representing the route.
* #param defaultColour default colour to draw route in.
*/
public RouteOverlay(final Route route, final int defaultColour) {
super();
routePoints = route.getPoints();
colour = defaultColour;
path = new Path();
p = new Point();
paint = new Paint();
}
#Override
public final void draw(final Canvas c, final MapView mv,
final boolean shadow) {
super.draw(c, mv, shadow);
paint.setColor(colour);
paint.setAlpha(ALPHA);
paint.setAntiAlias(true);
paint.setStrokeWidth(STROKE);
paint.setStyle(Paint.Style.STROKE);
redrawPath(mv);
c.drawPath(path, paint);
}
/**
* Set the colour to draw this route's overlay with.
*
* #param c Int representing colour.
*/
public final void setColour(final int c) {
colour = c;
}
/**
* Clear the route overlay.
*/
public final void clear() {
routePoints.clear();
}
/**
* Recalculate the path accounting for changes to
* the projection and routePoints.
* #param mv MapView the path is drawn to.
*/
private void redrawPath(final MapView mv) {
final Projection prj = mv.getProjection();
path.rewind();
final Iterator<GeoPoint> it = routePoints.iterator();
prj.toPixels(it.next(), p);
path.moveTo(p.x, p.y);
while (it.hasNext()) {
prj.toPixels(it.next(), p);
path.lineTo(p.x, p.y);
}
path.setLastPoint(p.x, p.y);
}
}
Segment.java
import com.google.android.maps.GeoPoint;
public class Segment {
/** Points in this segment. **/
private GeoPoint start;
/** Turn instruction to reach next segment. **/
private String instruction;
/** Length of segment. **/
private int length;
/** Distance covered. **/
private double distance;
/**
* Create an empty segment.
*/
public Segment() {
}
/**
* Set the turn instruction.
* #param turn Turn instruction string.
*/
public void setInstruction(final String turn) {
this.instruction = turn;
}
/**
* Get the turn instruction to reach next segment.
* #return a String of the turn instruction.
*/
public String getInstruction() {
return instruction;
}
/**
* Add a point to this segment.
* #param point GeoPoint to add.
*/
public void setPoint(final GeoPoint point) {
start = point;
}
/** Get the starting point of this
* segment.
* #return a GeoPoint
*/
public GeoPoint startPoint() {
return start;
}
/** Creates a segment which is a copy of this one.
* #return a Segment that is a copy of this one.
*/
public Segment copy() {
final Segment copy = new Segment();
copy.start = start;
copy.instruction = instruction;
copy.length = length;
copy.distance = distance;
return copy;
}
/**
* #param length the length to set
*/
public void setLength(final int length) {
this.length = length;
}
/**
* #return the length
*/
public int getLength() {
return length;
}
/**
* #param distance the distance to set
*/
public void setDistance(double distance) {
this.distance = distance;
}
/**
* #return the distance
*/
public double getDistance() {
return distance;
}
}
XMLParser.java
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import com.monumentos.log.Logger;
public class XMLParser {
// names of the XML tags
protected static final String MARKERS = "markers";
protected static final String MARKER = "marker";
protected URL feedUrl;
protected XMLParser(final String feedUrl) {
try {
this.feedUrl = new URL(feedUrl);
} catch (MalformedURLException e) {
Logger.appendLog( "XML parser - " + feedUrl);
}
}
protected InputStream getInputStream() {
try {
return feedUrl.openConnection().getInputStream();
} catch (IOException e) {
Logger.appendLog( "XML parser - " + feedUrl);
return null;
}
}
}
Hope it will helps you.
Calling api example:
Parser parser;
String jsonURL = "http://maps.googleapis.com/maps/api/directions/json?";
final StringBuffer sBuf = new StringBuffer(jsonURL);
sBuf.append("origin=");
sBuf.append( points.get(0).getLatitudeE6()/1E6);
sBuf.append(',');
sBuf.append(points.get(0).getLongitudeE6()/1E6);
sBuf.append("&destination=");
sBuf.append(points.get(points.size()-1).getLatitudeE6()/1E6);
sBuf.append(',');
sBuf.append(points.get(points.size()-1).getLongitudeE6()/1E6);
sBuf.append("&sensor=true&mode="+routeMode);
Logger.appendLog(sBuf.toString());
parser = new GoogleParser(sBuf.toString());
Route r = parser.parse();
You can parsing them using google http java client. Try this example
Related
Good Day!
I need help in developing my android app. is this possible to change the default name of speaker label to a custom one like a person name. i would like to create like this conversation as I example..
Jhon: Hi
Marie: Hello
Jhon: Good Day To you marie..
Marie:......
Please help i need help if is this possible to change the default name of speaker label i need your help
i created like this
private RecognizeOptions getRecognizeOptions(InputStream captureStream) {
return new RecognizeOptions.Builder()
.audio(captureStream)
.contentType(ContentType.OPUS.toString())
.model("en-US_BroadbandModel")
.interimResults(true)
.inactivityTimeout(2000)
.timestamps(true)
.speakerLabels(true)
.maxAlternatives(3)
.smartFormatting(true)
.timestamps(true)
.wordConfidence(true)
.build();
}
this is the method of .speakerLabels
public class SpeakerLabelsDiarization {
public static class RecoToken {
private Double startTime;
private Double endTime;
private Long speaker;
private String word;
private Boolean spLabelIsFinal;
/**
* Instantiates a new reco token.
*
* #param speechTimestamp the speech timestamp
*/
RecoToken(SpeechTimestamp speechTimestamp) {
startTime = speechTimestamp.getStartTime();
endTime = speechTimestamp.getEndTime();
word = speechTimestamp.getWord();
}
/**
* Instantiates a new reco token.
*
* #param speakerLabel the speaker label
*/
RecoToken(SpeakerLabelsResult speakerLabel) {
startTime = Double.valueOf(speakerLabel.getFrom());
endTime = Double.valueOf(speakerLabel.getTo());
speaker = speakerLabel.getSpeaker();
}
/**
* Update from.
*
* #param speechTimestamp the speech timestamp
*/
public void updateFrom(SpeechTimestamp speechTimestamp) {
word = speechTimestamp.getWord();
}
/**
* Update from.
*
* #param speakerLabel the speaker label
*/
public void updateFrom(SpeakerLabelsResult speakerLabel) {
speaker = speakerLabel.getSpeaker();
}
}
/**
* The Class Utterance.
*/
public static class Utterance {
private Integer speaker;
private String transcript = "";
/**
* Instantiates a new utterance.
*
* #param speaker the speaker
* #param transcript the transcript
*/
public Utterance(final Integer speaker, final String transcript) {
this.speaker = speaker;
this.transcript = transcript;
}
}
/**
* The Class RecoTokens.
*/
public static class RecoTokens {
private Map<Double, RecoToken> recoTokenMap;
/**
* Instantiates a new reco tokens.
*/
public RecoTokens() {
recoTokenMap = new LinkedHashMap<Double, RecoToken>();
}
/**
* Adds the.
*
* #param speechResults the speech results
*/
public void add(SpeechRecognitionResults speechResults) {
if (speechResults.getResults() != null)
for (int i = 0; i < speechResults.getResults().size(); i++) {
SpeechRecognitionResult transcript = speechResults.getResults().get(i);
if (transcript.isFinalResults()) {
SpeechRecognitionAlternative speechAlternative = transcript.getAlternatives().get(0);
for (int ts = 0; ts < speechAlternative.getTimestamps().size(); ts++) {
SpeechTimestamp speechTimestamp = speechAlternative.getTimestamps().get(ts);
add(speechTimestamp);
}
}
}
if (speechResults.getSpeakerLabels() != null)
for (int i = 0; i < speechResults.getSpeakerLabels().size(); i++) {
add(speechResults.getSpeakerLabels().get(i));
}
}
/**
* Adds the.
*
* #param speechTimestamp the speech timestamp
*/
public void add(SpeechTimestamp speechTimestamp) {
RecoToken recoToken = recoTokenMap.get(speechTimestamp.getStartTime());
if (recoToken == null) {
recoToken = new RecoToken(speechTimestamp);
recoTokenMap.put(speechTimestamp.getStartTime(), recoToken);
} else {
recoToken.updateFrom(speechTimestamp);
}
}
/**
* Adds the.
*
* #param speakerLabel the speaker label
*/
public void add(SpeakerLabelsResult speakerLabel) {
RecoToken recoToken = recoTokenMap.get(speakerLabel.getFrom());
if (recoToken == null) {
recoToken = new RecoToken(speakerLabel);
recoTokenMap.put(Double.valueOf(speakerLabel.getFrom()), recoToken);
} else {
recoToken.updateFrom(speakerLabel);
}
if (speakerLabel.isFinalResults()) {
markTokensBeforeAsFinal(speakerLabel.getFrom());
report();
cleanFinal();
}
}
private void markTokensBeforeAsFinal(Float from) {
Map<Double, RecoToken> recoTokenMap = new LinkedHashMap<>();
for (RecoToken rt : recoTokenMap.values()) {
if (rt.startTime <= from)
rt.spLabelIsFinal = true;
}
}
/**
* Report.
*/
public void report() {
List<Utterance> uttterances = new ArrayList<Utterance>();
Utterance currentUtterance = new Utterance(0, "");
for (RecoToken rt : recoTokenMap.values()) {
if (currentUtterance.speaker != Math.toIntExact(rt.speaker)) {
uttterances.add(currentUtterance);
currentUtterance = new Utterance(Math.toIntExact(rt.speaker), "");
}
currentUtterance.transcript = currentUtterance.transcript + rt.word + " ";
}
uttterances.add(currentUtterance);
String result = GsonSingleton.getGson().toJson(uttterances);
System.out.println(result);
}
private void cleanFinal() {
Set<Map.Entry<Double, RecoToken>> set = recoTokenMap.entrySet();
for (Map.Entry<Double, RecoToken> e : set) {
if (e.getValue().spLabelIsFinal) {
recoTokenMap.remove(e.getKey());
}
}
}
}
private static CountDownLatch lock = new CountDownLatch(1);
}
the output in that is like this`
speaker 0: Hi
speaker 1: Hello
speaker 0: Good Day To you marie..
speaker 1:......
and i would like to output like this
Jhon: Hi
Marie: Hello
Jhon: Good Day To you marie..
Marie:......
my question is. Is this possible to create like that in ibm watspon speech to text api because i read in their documentation their are not mentioning on how to change the labels i just want to clarify it if is this possible
There is nothing in the API nor the documentation to suggest that it is possible to modify the labels in the output using the service itself. https://cloud.ibm.com/docs/services/speech-to-text/output.html#speaker_labels
I have source code which is able to scan for BLE devies which are temp sensors, but when scanning it will not show any other BLE decies. I want to modify this code attached so that I can scan and view all BLE devices, regardless if it is a temp sensor. Can someone please explain me or show me how i can do this. here are the codes snippets to grab BLE Temp sensor data.
package no.nordicsemi.android.nrftemp.ble;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import no.nordicsemi.android.nrftemp.ble.parser.TemperatureData;
import no.nordicsemi.android.nrftemp.ble.parser.TemperatureDataParser;
import no.nordicsemi.android.nrftemp.database.DatabaseHelper;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.os.Handler;
public class TemperatureManager implements BluetoothAdapter.LeScanCallback {
/** An minimal interval between each data row in the database for a single device */
private static final long DATA_INTERVAL = 60 * 5 * 1000L; // ms
private BluetoothAdapter mBluetoothAdapter;
private DatabaseHelper mDatabaseHelper;
private List<TemperatureManagerCallback> mListeners;
public TemperatureManager(final Context context, final DatabaseHelper databaseHelper) {
final BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
mDatabaseHelper = databaseHelper;
mListeners = new ArrayList<TemperatureManagerCallback>(2);
}
public void addCallback(final TemperatureManagerCallback callback) {
mListeners.add(callback);
}
public void removeCallback(final TemperatureManagerCallback callback) {
mListeners.remove(callback);
}
private void fireOnDevicesScanned() {
for (TemperatureManagerCallback callback : mListeners)
callback.onDevicesScaned();
}
private void fireOnRssiUpdate(final long sensorId, final int rssi) {
for (TemperatureManagerCallback callback : mListeners)
callback.onRssiUpdate(sensorId, rssi);
}
/**
* Starts scanning for temperature data. Call {#link #stopScan()} when done to save the power.
*/
public void startScan() {
mBluetoothAdapter.startLeScan(this);
}
/**
* Starts scanning for temperature data. Call {#link #stopScan()} when done to save the power.
*/
public void startScan(final long period) {
mBluetoothAdapter.startLeScan(this);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
stopScan();
}
}, period);
}
/**
* Stops scanning for temperature data from BLE sensors.
*/
public void stopScan() {
mBluetoothAdapter.stopLeScan(this);
}
#Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
final TemperatureData td = TemperatureDataParser.parse(device, scanRecord);
if (!td.isValid())
return;
final long now = Calendar.getInstance().getTimeInMillis();
final long then = mDatabaseHelper.getLastTimestamp(td.getAddress());
if (now - then > DATA_INTERVAL) {
mDatabaseHelper.addNewSensorData(device.getAddress(), device.getName(), now,
td.getTemp(), td.getBattery());
fireOnDevicesScanned();
}
final long sensorId = mDatabaseHelper.findSensor(device.getAddress());
final int rssiPercent = (int) (100.0f * (127.0f + rssi) / 127.0f + 20.0f);
mDatabaseHelper.updateSensorRssi(sensorId, rssiPercent);
fireOnRssiUpdate(sensorId, rssiPercent);
}
/**
* Return <code>true</code> if Bluetooth is currently enabled and ready for use.
*
* #return <code>true</code> if the local adapter is turned on
*/
public boolean isEnabled() {
return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled();
}
}
package no.nordicsemi.android.nrftemp.ble.parser;
import android.bluetooth.BluetoothDevice;
/**
* Domain class contains data obtained from a single advertising package from a temperature sensor.
*/
public class TemperatureData {
/** The device address */
private final String address;
/** The device name */
private String name;
/** The temperature value */
private double temp;
/** Battery status (number 0-100 in percent) */
private int battery = 0xFF; // unknown value
/**
* The flag whether the data are valid (holds real temperature measurement or not)
*/
private boolean valid;
public TemperatureData(BluetoothDevice device) {
address = device.getAddress();
name = device.getName();
}
public String getAddress() {
return address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getTemp() {
return temp;
}
public void setTemp(double temp) {
this.temp = temp;
this.valid = true;
}
public int getBattery() {
return battery;
}
public void setBattery(int battery) {
this.battery = battery;
}
public boolean isValid() {
return valid;
}
}
package no.nordicsemi.android.nrftemp.ble.parser;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import android.bluetooth.BluetoothDevice;
import android.util.Log;
public class TemperatureDataParser {
private static final String TAG = "TemperatureDataParser";
private static final int FLAGS = 0x02; // "Flags" Data Type (See section 18.1 of Core_V4.0.pdf)
private static final int LOCAL_NAME = 0x09; // "Complete Local Name" Data Type (See section 18.3 of Core_V4.0.pdf)
private static final int SERVICE_DATA = 0x16; // "Service Data" Data Type (See section 18.10 of Core_V4.0.pdf)
private static final short TEMPERATURE_SERVICE_UUID = 0x1809;
private static final short BATTERY_SERVICE_UUID = 0x180F;
private static final short DEVICE_INFORMATION_SERVICE_UUID = 0x180A;
/**
* Parses the advertising package obtained by BLE device
*
* #param data
* the data obtained (EIR data). Read Bluetooth Core Specification v4.0 (Core_V4.0.pdf -> Vol.3 -> Part C -> Section 8) for details
* #return the parsed temperature data
* #throws ParseException
* thrown when the given data does not fit the expected format
*/
public static TemperatureData parse(final BluetoothDevice device, final byte[] data) {
final TemperatureData td = new TemperatureData(device);
/*
* First byte of each EIR Data Structure has it's length (1 octet).
* There comes the EIR Data Type (n bytes) and (length - n bytes) of data.
* See Core_V4.0.pdf -> Vol.3 -> Part C -> Section 8 for details
*/
for (int i = 0; i < data.length;) {
final int eirLength = data[i];
// check whether there is no more to read
if (eirLength == 0)
break;
final int eirDataType = data[++i];
switch (eirDataType) {
case FLAGS:
// do nothing
break;
case LOCAL_NAME:
/*
* Local name data structure contains length - 1 bytes of the device name (1 byte for the data type)
*/
final String name = decodeLocalName(data, i + 1, eirLength - 1);
td.setName(name);
break;
case SERVICE_DATA:
/*
* First 2 bytes of service data are the 16-bit Service UUID in reverse order. The rest is service specific data.
*/
final short serviceUUID = decodeServiceUUID(data, i + 1);
switch (serviceUUID) {
case BATTERY_SERVICE_UUID:
final int battery = decodeBatteryLevel(data, i + 3);
td.setBattery(battery);
break;
case TEMPERATURE_SERVICE_UUID:
final double temp = decodeTempLevel(data, i + 3);
td.setTemp(temp);
break;
case DEVICE_INFORMATION_SERVICE_UUID:
// do nothing
break;
}
break;
default:
break;
}
i += eirLength;
}
return td;
}
private static String decodeLocalName(final byte[] data, final int start, final int length) {
try {
return new String(data, start, length, "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Unable to convert the local name to UTF-8", e);
return null;
}
}
private static short decodeServiceUUID(final byte[] data, final int start) {
return (short) ((data[start + 1] << 8) | data[start]);
}
private static int decodeBatteryLevel(final byte[] data, final int start) {
/*
* Battery level is a 1 byte number 0-100 (0x64). Value 255 (0xFF) is used for illegal measurement values
*/
return data[start];
}
private static float decodeTempLevel(final byte[] data, final int start) {
return bytesToFloat(data[start], data[start + 1], data[start + 2], data[start + 3]);
}
/**
* Convert signed bytes to a 32-bit short float value.
*/
private static float bytesToFloat(byte b0, byte b1, byte b2, byte b3) {
int mantissa = unsignedToSigned(unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8) + (unsignedByteToInt(b2) << 16), 24);
return (float) (mantissa * Math.pow(10, b3));
}
/**
* Convert a signed byte to an unsigned int.
*/
private static int unsignedByteToInt(byte b) {
return b & 0xFF;
}
/**
* Convert an unsigned integer value to a two's-complement encoded signed value.
*/
private static int unsignedToSigned(int unsigned, int size) {
if ((unsigned & (1 << size - 1)) != 0) {
unsigned = -1 * ((1 << size - 1) - (unsigned & ((1 << size - 1) - 1)));
}
return unsigned;
}
}
As far as I can see, the code is scanning for every BLE device already, there are no service uuid restrictions in the scanning mBluetoothAdapter.startLeScan(this);
The issue with this code (as with many examples) is that it assumes every device to be of their own type (Temperature sensor in this case).
The assumption is here:
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
final TemperatureData td = TemperatureDataParser.parse(device, scanRecord);
The only way to know what services a device support is by connecting to it, do service discovery and the check for the supported services.
Regards, Rob.
I'm developing an app where i need to know the path between the current user posistion and a point of interest.
I'm using android 2.3.3, google maps android v2 and direction api.
My problem is that all the code i have found is for the old version of the maps, and I also tried to adapt the code but i failed. I try to change GeoPoint (not supported in this new versione) in LatLng.
the problem is that i can't display the path, to do it i create a new polyline and i add it to the map.
i post my code:
Parser:
public interface Parser {
public Route parse();
}
XMLParser
public class XMLParser {
// names of the XML tags
protected static final String MARKERS = "markers";
protected static final String MARKER = "marker";
protected URL feedUrl;
protected XMLParser(final String feedUrl) {
try {
this.feedUrl = new URL(feedUrl);
} catch (MalformedURLException e) {
Log.e(e.getMessage(), "XML parser - " + feedUrl);
}
}
protected InputStream getInputStream() {
try {
return feedUrl.openConnection().getInputStream();
} catch (IOException e) {
Log.e(e.getMessage(), "XML parser - " + feedUrl);
return null;
}
}
}
JsonParser (parse the google direction json)
public class JsonParser extends XMLParser implements Parser {
/** Distance covered. **/
private int distance;
public JsonParser(String feedUrl) {
super(feedUrl);
}
/**
* Parses a url pointing to a Google JSON object to a Route object.
* #return a Route object based on the JSON object.
*/
public Route parse() {
// turn the stream into a string
final String result = convertStreamToString(this.getInputStream());
//Create an empty route
final Route route = new Route();
//Create an empty segment
final Segment segment = new Segment();
try {
//Tranform the string into a json object
final JSONObject json = new JSONObject(result);
//Get the route object
final JSONObject jsonRoute = json.getJSONArray("routes").getJSONObject(0);
//Get the leg, only one leg as we don't support waypoints
final JSONObject leg = jsonRoute.getJSONArray("legs").getJSONObject(0);
//Get the steps for this leg
final JSONArray steps = leg.getJSONArray("steps");
//Number of steps for use in for loop
final int numSteps = steps.length();
//Set the name of this route using the start & end addresses
route.setName(leg.getString("start_address") + " to " + leg.getString("end_address"));
//Get google's copyright notice (tos requirement)
route.setCopyright(jsonRoute.getString("copyrights"));
//Get the total length of the route.
route.setLength(leg.getJSONObject("distance").getInt("value"));
//Get any warnings provided (tos requirement)
if (!jsonRoute.getJSONArray("warnings").isNull(0)) {
route.setWarning(jsonRoute.getJSONArray("warnings").getString(0));
}
/* Loop through the steps, creating a segment for each one and
* decoding any polylines found as we go to add to the route object's
* map array. Using an explicit for loop because it is faster!
*/
for (int i = 0; i < numSteps; i++) {
//Get the individual step
final JSONObject step = steps.getJSONObject(i);
//Get the start position for this step and set it on the segment
final JSONObject start = step.getJSONObject("start_location");
final LatLng position = new LatLng(start.getDouble("lat"), start.getDouble("lng"));
segment.setPoint(position);
//Set the length of this segment in metres
final int length = step.getJSONObject("distance").getInt("value");
distance += length;
segment.setLength(length);
segment.setDistance(distance/1000);
//Strip html from google directions and set as turn instruction
segment.setInstruction(step.getString("html_instructions").replaceAll("<(.*?)*>", ""));
//Retrieve & decode this segment's polyline and add it to the route.
route.addPoints(decodePolyLine(step.getJSONObject("polyline").getString("points")));
//Push a copy of the segment to the route
route.addSegment(segment.copy());
}
} catch (JSONException e) {
Log.e(e.getMessage(), "Google JSON Parser - " + feedUrl);
}
return route;
}
/**
* Convert an inputstream to a string.
* #param input inputstream to convert.
* #return a String of the inputstream.
*/
private static String convertStreamToString(final InputStream input) {
final BufferedReader reader = new BufferedReader(new InputStreamReader(input));
final StringBuilder sBuf = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sBuf.append(line);
}
} catch (IOException e) {
Log.e(e.getMessage(), "Google parser, stream2string");
} finally {
try {
input.close();
} catch (IOException e) {
Log.e(e.getMessage(), "Google parser, stream2string");
}
}
return sBuf.toString();
}
/**
* Decode a polyline string into a list of LatLng.
* #param poly polyline encoded string to decode.
* #return the list of GeoPoints represented by this polystring.
*/
private List<LatLng> decodePolyLine(final String poly) {
int len = poly.length();
int index = 0;
List<LatLng> decoded = new LinkedList<LatLng>();
int lat = 0;
int lng = 0;
while (index < len) {
int b;
int shift = 0;
int result = 0;
do {
b = poly.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = poly.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lng += dlng;
decoded.add(new LatLng((lat / 1E5),(lng / 1E5)));
}
return decoded;
}
}
Route (to save json info)
public class Route {
private String name;
private final List<LatLng> points;
private List<Segment> segments;
private String copyright;
private String warning;
private String country;
private int length;
private String polyline;
public Route() {
points = new LinkedList<LatLng>();
segments = new LinkedList<Segment>();
}
public void addPoint(final LatLng p) {
points.add(p);
}
public void addPoints(final List<LatLng> points) {
this.points.addAll(points);
}
public List<LatLng> getPoints() {
return points;
}
public void addSegment(final Segment s) {
segments.add(s);
}
public List<Segment> getSegments() {
return segments;
}
/**
* #param name the name to set
*/
public void setName(final String name) {
this.name = name;
}
/**
* #return the name
*/
public String getName() {
return name;
}
/**
* #param copyright the copyright to set
*/
public void setCopyright(String copyright) {
this.copyright = copyright;
}
/**
* #return the copyright
*/
public String getCopyright() {
return copyright;
}
/**
* #param warning the warning to set
*/
public void setWarning(String warning) {
this.warning = warning;
}
/**
* #return the warning
*/
public String getWarning() {
return warning;
}
/**
* #param country the country to set
*/
public void setCountry(String country) {
this.country = country;
}
/**
* #return the country
*/
public String getCountry() {
return country;
}
/**
* #param length the length to set
*/
public void setLength(int length) {
this.length = length;
}
/**
* #return the length
*/
public int getLength() {
return length;
}
/**
* #param polyline the polyline to set
*/
public void setPolyline(String polyline) {
this.polyline = polyline;
}
/**
* #return the polyline
*/
public String getPolyline() {
return polyline;
}
}
Segment:
public class Segment {
/** Points in this segment. **/
private LatLng start;
/** Turn instruction to reach next segment. **/
private String instruction;
/** Length of segment. **/
private int length;
/** Distance covered. **/
private double distance;
/**
* Create an empty segment.
*/
public Segment() {
}
/**
* Set the turn instruction.
* #param turn Turn instruction string.
*/
public void setInstruction(final String turn) {
this.instruction = turn;
}
/**
* Get the turn instruction to reach next segment.
* #return a String of the turn instruction.
*/
public String getInstruction() {
return instruction;
}
/**
* Add a point to this segment.
* #param point LatLng to add.
*/
public void setPoint(LatLng point) {
start = point;
}
/** Get the starting point of this
* segment.
* #return a LatLng
*/
public LatLng startPoint() {
return start;
}
/** Creates a segment which is a copy of this one.
* #return a Segment that is a copy of this one.
*/
public Segment copy() {
final Segment copy = new Segment();
copy.start = start;
copy.instruction = instruction;
copy.length = length;
copy.distance = distance;
return copy;
}
/**
* #param length the length to set
*/
public void setLength(final int length) {
this.length = length;
}
/**
* #return the length
*/
public int getLength() {
return length;
}
/**
* #param distance the distance to set
*/
public void setDistance(double distance) {
this.distance = distance;
}
/**
* #return the distance
*/
public double getDistance() {
return distance;
}
}
My MainActivity (there are 326 code line because of user localization, you can find it on google developer site, so we can just suppose to have two static point A and B and I want to go from A to B):
public class MainActivity extends FragmentActivity{
private GoogleMap map;
private Marker currentLocation;
private PolylineOptions pathLine;
private LatLng imhere = new LatLng(41.8549038,12.4618208);
private LatLng poi = new LatLng(41.89000,12.49324);
private LocationManager mLocationManager;
private Handler mHandler;
private boolean mUseBoth;
private Context context;
// Keys for maintaining UI states after rotation.
private static final String KEY_BOTH = "use_both";
// UI handler codes.
private static final int UPDATE_LATLNG = 2;
private static final int FIVE_SECONDS = 5000;
private static final int THREE_METERS = 3;
private static final int TWO_MINUTES = 1000 * 60 * 2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
Marker colosseoMarker = map.addMarker(new MarkerOptions()
.position(colosseo)
.title("Start")
.snippet("poi")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher)));
Marker current pos = map.addMarker(new MarkerOptions()
.position(imhere)
.title("i'm here")
.snippet("here!")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher)));
context =this ;
map.setOnMarkerClickListener(new OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker) {
final String[] options = {"Calcola il Percorso"};
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("Ottieni Informazioni aggiuntive");
builder.setPositiveButton("Calcola Percorso",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
LatLng start = new LatLng(imhere.latitude,imhere.longitude);
LatLng dest = new LatLng(poi.latitude, poi.longitude);
Route route = drawPath(start, dest);
List<LatLng> list= route.getPoints();
if(pathLine!= null) pathline =null;
pathLine = new PolylineOptions();
pathLine.addAll(list);
pathLine.color(Color.rgb(0,191,255));
map.addPolyline(pathLine);
}
});
AlertDialog alert = builder.create();
alert.show();
Toast.makeText(MainActivity.this, marker.getSnippet(),Toast.LENGTH_SHORT).show();
return true;
}
});
map.animateCamera(CameraUpdateFactory.newLatLngZoom(imhere, 12));
}
}
};
// Get a reference to the LocationManager object.
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
}
private Route drawPath(LatLng start, LatLng dest) {
Parser parser;
String jsonURL = "http://maps.google.com/maps/api/directions/json?";
final StringBuffer sBuf = new StringBuffer(jsonURL);
sBuf.append("origin=");
sBuf.append(start.latitude);
sBuf.append(',');
sBuf.append(start.longitude);
sBuf.append("&destination=");
sBuf.append(dest.latitude);
sBuf.append(',');
sBuf.append(dest.longitude);
sBuf.append("&sensor=true&mode=walking");
parser = new JsonParser(sBuf.toString());
Route r = parser.parse();
return r;
}
}
every suggestion is well accepted
If you don't need custom code try this lib https://github.com/jd-alexander/Google-Directions-Android only a few lines of code to do what you need.
I am doing like the following. I think this will help you.
Marker interestedMarker;
private void plot_direction(){
if (currentSelectedPin !=null) {
LatLng origin = new LatLng(currentLocation.getLatitude(),currentLocation.getLongitude());
new GoogleMapDirection(getActivity(), origin, interestedMarker.getPosition(), new DirectionListener() {
#Override
public void onDirectionPointsReceived(ArrayList<RouteModel> routeList, String distance, String duration) {
PolylineOptions lineOptions = null;
for (RouteModel route : routeList) {
lineOptions = new PolylineOptions();
lineOptions.addAll(route.getSteps());
lineOptions.width(20);
lineOptions.color(ContextCompat.getColor(getContext(), R.color.map_route));
}
//For removing existing line
if (routeMap!=null){
routeMap.remove();
}
if(lineOptions != null) {
routeMap = mMap.addPolyline(lineOptions);
}
}
});
}
}
GoogleMapDirection class is as follows
public class GoogleMapDirection {
private DirectionListener listener;
public GoogleMapDirection(final Activity activity, LatLng source, LatLng destination, DirectionListener listener){
this.listener=listener;
String url = null;
try {
url = "https://maps.googleapis.com/maps/api/directions/json?origin="+ URLEncoder.encode(Double.toString(source.latitude) + "," + Double.toString(source.longitude), "UTF-8") + "&destination=" + URLEncoder.encode(Double.toString(destination.latitude) + "," + Double.toString(destination.longitude), "UTF-8") + "&mode=driving&sensor=false&key=" + Config.GOOGLE_API_BROWSER_KEY;
Print.d(url);
} catch (UnsupportedEncodingException e) {
Print.exception(e);
}
JSONObject parameters = new JSONObject();
VolleyJsonBodyRequest.execute(activity, url, parameters, new VolleyResponseListener() {
#Override
public void onResponse(JSONObject response) {
try {
if (response.getString("status").equals("OK")) {
String distance = "NA";
String duration = "NA";
if (response.has("routes")){
JSONArray routesJArray = response.getJSONArray("routes");
if (routesJArray.length()>0){
if (routesJArray.getJSONObject(0).has("legs")){
JSONArray legsJArray = routesJArray.getJSONObject(0).getJSONArray("legs");
if (legsJArray.length()>0){
JSONObject firstLegsJObj = legsJArray.getJSONObject(0);
if (firstLegsJObj.has("distance")){
distance = firstLegsJObj.getJSONObject("distance").getString("text");
}
if (firstLegsJObj.has("duration")){
duration = firstLegsJObj.getJSONObject("duration").getString("text");
}
}
}
}
}
GoogleResponseParserTask task = new GoogleResponseParserTask(distance,duration);
task.execute(response);
}
} catch (JSONException e) {
Print.exception(e);
DialogWindow.showOK(activity, Config.MESSAGE_INVALID_RESPONSE_FORMAT, new DialogListenerOK() {
#Override
public void onOK() {
}
});
}
}
#Override
public void onErrorResponse(VolleyResponseError error) {
Print.e(error.getDetails());
DialogWindow.showOK(activity, error.getMessage(), new DialogListenerOK() {
#Override
public void onOK() {
}
});
}
});
}
/**
* A class to parse the Google Places in JSON format
*/
private class GoogleResponseParserTask extends AsyncTask<JSONObject, Integer, ArrayList<RouteModel>> {
String distance;
String duration;
private GoogleResponseParserTask(String distance, String duration){
this.distance=distance;
this.duration=duration;
}
#Override
protected ArrayList<RouteModel> doInBackground(JSONObject... jsonResponse) {
ArrayList<RouteModel> routes = null;
try {
routes = parse(jsonResponse[0]);
} catch (Exception e) {
Print.exception(e);
}
return routes;
}
#Override
protected void onPostExecute(ArrayList<RouteModel> result) {
listener.onDirectionPointsReceived(result,distance,duration);
}
}
/** Receives a JSONObject and returns a list of lists containing latitude and longitude */
public ArrayList<RouteModel> parse(JSONObject jObject){
ArrayList<RouteModel> routeList = new ArrayList<>() ;
JSONArray jRoutes;
JSONArray jLegs;
JSONArray jSteps;
try {
jRoutes = jObject.getJSONArray("routes");
/** Traversing all routes */
for(int i=0;i<jRoutes.length();i++){
jLegs = ( (JSONObject)jRoutes.get(i)).getJSONArray("legs");
ArrayList<LatLng> pointList = new ArrayList<>();
/** Traversing all legs */
for(int j=0;j<jLegs.length();j++){
jSteps = ((JSONObject)jLegs.get(j)).getJSONArray("steps");
JSONObject jDistance = ((JSONObject) jLegs.get(j)).getJSONObject("distance");
JSONObject jDuration = ((JSONObject) jLegs.get(j)).getJSONObject("duration");
String distance = jDistance.getString("text");
String duration = jDuration.getString("text");
/** Traversing all steps */
for(int k=0;k<jSteps.length();k++){
String polyline = (String)((JSONObject)((JSONObject)jSteps.get(k)).get("polyline")).get("points");
ArrayList<LatLng> stepList = decodePoly(polyline);
/** Traversing all points */
for(int l=0;l<stepList.size();l++){
LatLng point = new LatLng((stepList.get(l)).latitude, (stepList.get(l)).longitude);
pointList.add(point);
}
}
RouteModel routeModel = new RouteModel();
routeModel.setSteps(pointList);
routeModel.setDistance(distance);
routeModel.setDuration(duration);
routeList.add(routeModel);
}
}
} catch (JSONException e) {
e.printStackTrace();
}catch (Exception e){
}
return routeList;
}
/**
* Method to decode polyline points
* Courtesy : http://jeffreysambells.com/2010/05/27/decoding-polylines-from-google-maps-direction-api-with-java
* */
private ArrayList<LatLng> decodePoly(String encoded) {
ArrayList<LatLng> poly = new ArrayList<>();
int index = 0, len = encoded.length();
int lat = 0, lng = 0;
while (index < len) {
int b, shift = 0, result = 0;
do {
b = encoded.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = encoded.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lng += dlng;
LatLng p = new LatLng((((double) lat / 1E5)),
(((double) lng / 1E5)));
poly.add(p);
}
return poly;
}
//main activity in this class two errors shown below within the comments
import android.graphics.Color;
import android.os.Bundle;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
public class NewroutepathActivity extends MapActivity {
/** Called when the activity is first created. */
MapView mapView;
private String US_API;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//mapView = (MapView) findViewById(R.id.mapview);
MapView mapView = (MapView) findViewById(R.id.mapview); //or you can declare it directly with the API key
Route route = directions(new GeoPoint((int)(26.2*1E6),(int)(50.6*1E6)), new GeoPoint((int)(26.3*1E6),(int)(50.7*1E6)));
//the obove line also getting error
RouteOverlay routeOverlay = new RouteOverlay(route, Color.BLUE);
mapView.getOverlays().add(routeOverlay);
}
#Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
private Route directions(final GeoPoint start, final GeoPoint dest) {
Parser parser;
String jsonURL = "maps.google.com/maps/api/directions/json?";
final StringBuffer sBuf = new StringBuffer(jsonURL);
sBuf.append("origin=");
sBuf.append(start.getLatitudeE6()/1E6);
sBuf.append(',');
sBuf.append(start.getLongitudeE6()/1E6);
sBuf.append("&destination=");
sBuf.append(dest.getLatitudeE6()/1E6);
sBuf.append(',');
sBuf.append(dest.getLongitudeE6()/1E6);
sBuf.append("&sensor=true&mode=driving");
parser = new GoogleParser(sBuf.toString());
Route r = parser.parse();// here getting error
return r;
}
}
googleparser classes here one error
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.util.Log;
import com.google.android.maps.GeoPoint;
public class GoogleParser extends XMLParser implements Parser {
/** Distance covered. **/
private int distance;
public GoogleParser(String feedUrl) {
super(feedUrl);
}
/**
* Parses a url pointing to a Google JSON object to a Route object.
* #return a Route object based on the JSON object.
*/
public Route parse() {
// turn the stream into a string
final String result = convertStreamToString(this.getInputStream());
//The above line is getting one error
//Create an empty route
final Route route = new Route();
//Create an empty segment
final Segment segment = new Segment();
try {
//Tranform the string into a json object
final JSONObject json = new JSONObject(result);
//Get the route object
final JSONObject jsonRoute = json.getJSONArray("routes").getJSONObject(0);
//Get the leg, only one leg as we don't support waypoints
final JSONObject leg = jsonRoute.getJSONArray("legs").getJSONObject(0);
//Get the steps for this leg
final JSONArray steps = leg.getJSONArray("steps");
//Number of steps for use in for loop
final int numSteps = steps.length();
//Set the name of this route using the start & end addresses
route.setName(leg.getString("start_address") + " to " + leg.getString("end_address"));
//Get google's copyright notice (tos requirement)
route.setCopyright(jsonRoute.getString("copyrights"));
//Get the total length of the route.
route.setLength(leg.getJSONObject("distance").getInt("value"));
//Get any warnings provided (tos requirement)
if (!jsonRoute.getJSONArray("warnings").isNull(0)) {
route.setWarning(jsonRoute.getJSONArray("warnings").getString(0));
}
/* Loop through the steps, creating a segment for each one and
* decoding any polylines found as we go to add to the route object's
* map array. Using an explicit for loop because it is faster!
*/
for (int i = 0; i < numSteps; i++) {
//Get the individual step
final JSONObject step = steps.getJSONObject(i);
//Get the start position for this step and set it on the segment
final JSONObject start = step.getJSONObject("start_location");
final GeoPoint position = new GeoPoint((int) (start.getDouble("lat")*1E6),
(int) (start.getDouble("lng")*1E6));
segment.setPoint(position);
//Set the length of this segment in metres
final int length = step.getJSONObject("distance").getInt("value");
distance += length;
segment.setLength(length);
segment.setDistance(distance/1000);
//Strip html from google directions and set as turn instruction
segment.setInstruction(step.getString("html_instructions").replaceAll("<(.*?)*>", ""));
//Retrieve & decode this segment's polyline and add it to the route.
route.addPoints(decodePolyLine(step.getJSONObject("polyline").getString("points")));
//Push a copy of the segment to the route
route.addSegment(segment.copy());
}
} catch (JSONException e) {
Log.e(e.getMessage(), "Google JSON Parser - " + feedUrl);
}
return route;
}
/**
* Convert an inputstream to a string.
* #param input inputstream to convert.
* #return a String of the inputstream.
*/
private static String convertStreamToString(final InputStream input) {
final BufferedReader reader = new BufferedReader(new InputStreamReader(input));
final StringBuilder sBuf = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sBuf.append(line);
}
} catch (IOException e) {
Log.e(e.getMessage(), "Google parser, stream2string");
} finally {
try {
input.close();
} catch (IOException e) {
Log.e(e.getMessage(), "Google parser, stream2string");
}
}
return sBuf.toString();
}
/**
* Decode a polyline string into a list of GeoPoints.
* #param poly polyline encoded string to decode.
* #return the list of GeoPoints represented by this polystring.
*/
private List<GeoPoint> decodePolyLine(final String poly) {
int len = poly.length();
int index = 0;
List<GeoPoint> decoded = new ArrayList<GeoPoint>();
int lat = 0;
int lng = 0;
while (index < len) {
int b;
int shift = 0;
int result = 0;
do {
b = poly.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = poly.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lng += dlng;
decoded.add(new GeoPoint(
(int) (lat*1E6 / 1E5), (int) (lng*1E6 / 1E5)));
}
return decoded;
}
}
That happened to me too. To solve it - in function 'direction', when you start to build the jsonURL string, add 'http://' at the beginning, just before 'map.google.com...'.
I think the problem here is that you are targeting newer APIs , that requires accessing the network not in the main thread. Change the definition of getInputStream() (At XMLParser?) to support networking in a seperate thread.
Can I parse kml file in order to display paths or points in Android? Please could you help me with that?
This is kml sample code which I would like to display in android google map:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>Paths</name>
<description>Examples of paths. Note that the tessellate tag is by default
set to 0. If you want to create tessellated lines, they must be authored
(or edited) directly in KML.</description>
<Style id="yellowLineGreenPoly">
<LineStyle>
<color>7f00ffff</color>
<width>4</width>
</LineStyle>
<PolyStyle>
<color>7f00ff00</color>
</PolyStyle>
</Style>
<Placemark>
<name>Absolute Extruded</name>
<description>Transparent green wall with yellow outlines</description>
<styleUrl>#yellowLineGreenPoly</styleUrl>
<LineString>
<extrude>1</extrude>
<tessellate>1</tessellate>
<altitudeMode>absolute</altitudeMode>
<coordinates> -112.2550785337791,36.07954952145647,2357
-112.2549277039738,36.08117083492122,2357
-112.2552505069063,36.08260761307279,2357
-112.2564540158376,36.08395660588506,2357
-112.2580238976449,36.08511401044813,2357
-112.2595218489022,36.08584355239394,2357
-112.2608216347552,36.08612634548589,2357
-112.262073428656,36.08626019085147,2357
-112.2633204928495,36.08621519860091,2357
-112.2644963846444,36.08627897945274,2357
-112.2656969554589,36.08649599090644,2357
</coordinates>
<LineString>
</Placemark>
</Document>
</kml>
When I'm loading this file to standard web google map it displays it nicely but when I'm trying the same thing with android google map it doesn't do that. It just takes me to some locations and that's it. I was thinking of changing listener class. Currently it looks like that:
private class MyLocationListener implements LocationListener
{
#Override
public void onLocationChanged(Location loc) {
if (loc != null) {
latitude = (loc.getLatitude() * 1E6);
longitude = (loc.getLongitude() * 1E6);
Toast.makeText(getBaseContext(),
"Location changed : Lat: " + latitude +
" Lng: " + longitude,
Toast.LENGTH_SHORT).show();
GeoPoint p = new GeoPoint(
(int) (loc.getLatitude() * 1E6),
(int) (loc.getLongitude() * 1E6));
mc.animateTo(p);
mapView.invalidate();
}
}
//---------------------------------------------------------------
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status,
Bundle extras) {
//TODO Auto-generated method stub
}
Please can someone tell me what's I'm doing wrong here?
In above code, you don't pass the kml data to your mapView anywhere in your code, as far as I can see.
To display the route, you should parse the kml data i.e. via SAX parser, then display the route markers on the map.
See the code below for an example, but it's not complete though - just for you as a reference and get some idea.
This is a simple bean I use to hold the route information I will be parsing.
package com.myapp.android.model.navigation;
import java.util.ArrayList;
import java.util.Iterator;
public class NavigationDataSet {
private ArrayList<Placemark> placemarks = new ArrayList<Placemark>();
private Placemark currentPlacemark;
private Placemark routePlacemark;
public String toString() {
String s= "";
for (Iterator<Placemark> iter=placemarks.iterator();iter.hasNext();) {
Placemark p = (Placemark)iter.next();
s += p.getTitle() + "\n" + p.getDescription() + "\n\n";
}
return s;
}
public void addCurrentPlacemark() {
placemarks.add(currentPlacemark);
}
public ArrayList<Placemark> getPlacemarks() {
return placemarks;
}
public void setPlacemarks(ArrayList<Placemark> placemarks) {
this.placemarks = placemarks;
}
public Placemark getCurrentPlacemark() {
return currentPlacemark;
}
public void setCurrentPlacemark(Placemark currentPlacemark) {
this.currentPlacemark = currentPlacemark;
}
public Placemark getRoutePlacemark() {
return routePlacemark;
}
public void setRoutePlacemark(Placemark routePlacemark) {
this.routePlacemark = routePlacemark;
}
}
And the SAX Handler to parse the kml:
package com.myapp.android.model.navigation;
import android.util.Log;
import com.myapp.android.myapp;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import com.myapp.android.model.navigation.NavigationDataSet;
import com.myapp.android.model.navigation.Placemark;
public class NavigationSaxHandler extends DefaultHandler{
// ===========================================================
// Fields
// ===========================================================
private boolean in_kmltag = false;
private boolean in_placemarktag = false;
private boolean in_nametag = false;
private boolean in_descriptiontag = false;
private boolean in_geometrycollectiontag = false;
private boolean in_linestringtag = false;
private boolean in_pointtag = false;
private boolean in_coordinatestag = false;
private StringBuffer buffer;
private NavigationDataSet navigationDataSet = new NavigationDataSet();
// ===========================================================
// Getter & Setter
// ===========================================================
public NavigationDataSet getParsedData() {
navigationDataSet.getCurrentPlacemark().setCoordinates(buffer.toString().trim());
return this.navigationDataSet;
}
// ===========================================================
// Methods
// ===========================================================
#Override
public void startDocument() throws SAXException {
this.navigationDataSet = new NavigationDataSet();
}
#Override
public void endDocument() throws SAXException {
// Nothing to do
}
/** Gets be called on opening tags like:
* <tag>
* Can provide attribute(s), when xml was like:
* <tag attribute="attributeValue">*/
#Override
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts) throws SAXException {
if (localName.equals("kml")) {
this.in_kmltag = true;
} else if (localName.equals("Placemark")) {
this.in_placemarktag = true;
navigationDataSet.setCurrentPlacemark(new Placemark());
} else if (localName.equals("name")) {
this.in_nametag = true;
} else if (localName.equals("description")) {
this.in_descriptiontag = true;
} else if (localName.equals("GeometryCollection")) {
this.in_geometrycollectiontag = true;
} else if (localName.equals("LineString")) {
this.in_linestringtag = true;
} else if (localName.equals("point")) {
this.in_pointtag = true;
} else if (localName.equals("coordinates")) {
buffer = new StringBuffer();
this.in_coordinatestag = true;
}
}
/** Gets be called on closing tags like:
* </tag> */
#Override
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
if (localName.equals("kml")) {
this.in_kmltag = false;
} else if (localName.equals("Placemark")) {
this.in_placemarktag = false;
if ("Route".equals(navigationDataSet.getCurrentPlacemark().getTitle()))
navigationDataSet.setRoutePlacemark(navigationDataSet.getCurrentPlacemark());
else navigationDataSet.addCurrentPlacemark();
} else if (localName.equals("name")) {
this.in_nametag = false;
} else if (localName.equals("description")) {
this.in_descriptiontag = false;
} else if (localName.equals("GeometryCollection")) {
this.in_geometrycollectiontag = false;
} else if (localName.equals("LineString")) {
this.in_linestringtag = false;
} else if (localName.equals("point")) {
this.in_pointtag = false;
} else if (localName.equals("coordinates")) {
this.in_coordinatestag = false;
}
}
/** Gets be called on the following structure:
* <tag>characters</tag> */
#Override
public void characters(char ch[], int start, int length) {
if(this.in_nametag){
if (navigationDataSet.getCurrentPlacemark()==null) navigationDataSet.setCurrentPlacemark(new Placemark());
navigationDataSet.getCurrentPlacemark().setTitle(new String(ch, start, length));
} else
if(this.in_descriptiontag){
if (navigationDataSet.getCurrentPlacemark()==null) navigationDataSet.setCurrentPlacemark(new Placemark());
navigationDataSet.getCurrentPlacemark().setDescription(new String(ch, start, length));
} else
if(this.in_coordinatestag){
if (navigationDataSet.getCurrentPlacemark()==null) navigationDataSet.setCurrentPlacemark(new Placemark());
//navigationDataSet.getCurrentPlacemark().setCoordinates(new String(ch, start, length));
buffer.append(ch, start, length);
}
}
}
and a simple placeMark bean:
package com.myapp.android.model.navigation;
public class Placemark {
String title;
String description;
String coordinates;
String address;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getCoordinates() {
return coordinates;
}
public void setCoordinates(String coordinates) {
this.coordinates = coordinates;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Finally the service class in my model that calls the calculation:
package com.myapp.android.model.navigation;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import com.myapp.android.myapp;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import android.util.Log;
public class MapService {
public static final int MODE_ANY = 0;
public static final int MODE_CAR = 1;
public static final int MODE_WALKING = 2;
public static String inputStreamToString (InputStream in) throws IOException {
StringBuffer out = new StringBuffer();
byte[] b = new byte[4096];
for (int n; (n = in.read(b)) != -1;) {
out.append(new String(b, 0, n));
}
return out.toString();
}
public static NavigationDataSet calculateRoute(Double startLat, Double startLng, Double targetLat, Double targetLng, int mode) {
return calculateRoute(startLat + "," + startLng, targetLat + "," + targetLng, mode);
}
public static NavigationDataSet calculateRoute(String startCoords, String targetCoords, int mode) {
String urlPedestrianMode = "http://maps.google.com/maps?" + "saddr=" + startCoords + "&daddr="
+ targetCoords + "&sll=" + startCoords + "&dirflg=w&hl=en&ie=UTF8&z=14&output=kml";
Log.d(myapp.APP, "urlPedestrianMode: "+urlPedestrianMode);
String urlCarMode = "http://maps.google.com/maps?" + "saddr=" + startCoords + "&daddr="
+ targetCoords + "&sll=" + startCoords + "&hl=en&ie=UTF8&z=14&output=kml";
Log.d(myapp.APP, "urlCarMode: "+urlCarMode);
NavigationDataSet navSet = null;
// for mode_any: try pedestrian route calculation first, if it fails, fall back to car route
if (mode==MODE_ANY||mode==MODE_WALKING) navSet = MapService.getNavigationDataSet(urlPedestrianMode);
if (mode==MODE_ANY&&navSet==null||mode==MODE_CAR) navSet = MapService.getNavigationDataSet(urlCarMode);
return navSet;
}
/**
* Retrieve navigation data set from either remote URL or String
* #param url
* #return navigation set
*/
public static NavigationDataSet getNavigationDataSet(String url) {
// urlString = "http://192.168.1.100:80/test.kml";
Log.d(myapp.APP,"urlString -->> " + url);
NavigationDataSet navigationDataSet = null;
try
{
final URL aUrl = new URL(url);
final URLConnection conn = aUrl.openConnection();
conn.setReadTimeout(15 * 1000); // timeout for reading the google maps data: 15 secs
conn.connect();
/* Get a SAXParser from the SAXPArserFactory. */
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
/* Get the XMLReader of the SAXParser we created. */
XMLReader xr = sp.getXMLReader();
/* Create a new ContentHandler and apply it to the XML-Reader*/
NavigationSaxHandler navSax2Handler = new NavigationSaxHandler();
xr.setContentHandler(navSax2Handler);
/* Parse the xml-data from our URL. */
xr.parse(new InputSource(aUrl.openStream()));
/* Our NavigationSaxHandler now provides the parsed data to us. */
navigationDataSet = navSax2Handler.getParsedData();
/* Set the result to be displayed in our GUI. */
Log.d(myapp.APP,"navigationDataSet: "+navigationDataSet.toString());
} catch (Exception e) {
// Log.e(myapp.APP, "error with kml xml", e);
navigationDataSet = null;
}
return navigationDataSet;
}
}
Drawing:
/**
* Does the actual drawing of the route, based on the geo points provided in the nav set
*
* #param navSet Navigation set bean that holds the route information, incl. geo pos
* #param color Color in which to draw the lines
* #param mMapView01 Map view to draw onto
*/
public void drawPath(NavigationDataSet navSet, int color, MapView mMapView01) {
Log.d(myapp.APP, "map color before: " + color);
// color correction for dining, make it darker
if (color == Color.parseColor("#add331")) color = Color.parseColor("#6C8715");
Log.d(myapp.APP, "map color after: " + color);
Collection overlaysToAddAgain = new ArrayList();
for (Iterator iter = mMapView01.getOverlays().iterator(); iter.hasNext();) {
Object o = iter.next();
Log.d(myapp.APP, "overlay type: " + o.getClass().getName());
if (!RouteOverlay.class.getName().equals(o.getClass().getName())) {
// mMapView01.getOverlays().remove(o);
overlaysToAddAgain.add(o);
}
}
mMapView01.getOverlays().clear();
mMapView01.getOverlays().addAll(overlaysToAddAgain);
String path = navSet.getRoutePlacemark().getCoordinates();
Log.d(myapp.APP, "path=" + path);
if (path != null && path.trim().length() > 0) {
String[] pairs = path.trim().split(" ");
Log.d(myapp.APP, "pairs.length=" + pairs.length);
String[] lngLat = pairs[0].split(","); // lngLat[0]=longitude lngLat[1]=latitude lngLat[2]=height
Log.d(myapp.APP, "lnglat =" + lngLat + ", length: " + lngLat.length);
if (lngLat.length<3) lngLat = pairs[1].split(","); // if first pair is not transferred completely, take seconds pair //TODO
try {
GeoPoint startGP = new GeoPoint((int) (Double.parseDouble(lngLat[1]) * 1E6), (int) (Double.parseDouble(lngLat[0]) * 1E6));
mMapView01.getOverlays().add(new RouteOverlay(startGP, startGP, 1));
GeoPoint gp1;
GeoPoint gp2 = startGP;
for (int i = 1; i < pairs.length; i++) // the last one would be crash
{
lngLat = pairs[i].split(",");
gp1 = gp2;
if (lngLat.length >= 2 && gp1.getLatitudeE6() > 0 && gp1.getLongitudeE6() > 0
&& gp2.getLatitudeE6() > 0 && gp2.getLongitudeE6() > 0) {
// for GeoPoint, first:latitude, second:longitude
gp2 = new GeoPoint((int) (Double.parseDouble(lngLat[1]) * 1E6), (int) (Double.parseDouble(lngLat[0]) * 1E6));
if (gp2.getLatitudeE6() != 22200000) {
mMapView01.getOverlays().add(new RouteOverlay(gp1, gp2, 2, color));
Log.d(myapp.APP, "draw:" + gp1.getLatitudeE6() + "/" + gp1.getLongitudeE6() + " TO " + gp2.getLatitudeE6() + "/" + gp2.getLongitudeE6());
}
}
// Log.d(myapp.APP,"pair:" + pairs[i]);
}
//routeOverlays.add(new RouteOverlay(gp2,gp2, 3));
mMapView01.getOverlays().add(new RouteOverlay(gp2, gp2, 3));
} catch (NumberFormatException e) {
Log.e(myapp.APP, "Cannot draw route.", e);
}
}
// mMapView01.getOverlays().addAll(routeOverlays); // use the default color
mMapView01.setEnabled(true);
}
This is the RouteOverlay class:
package com.myapp.android.activity.map.nav;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;
public class RouteOverlay extends Overlay {
private GeoPoint gp1;
private GeoPoint gp2;
private int mRadius=6;
private int mode=0;
private int defaultColor;
private String text="";
private Bitmap img = null;
public RouteOverlay(GeoPoint gp1,GeoPoint gp2,int mode) { // GeoPoint is a int. (6E)
this.gp1 = gp1;
this.gp2 = gp2;
this.mode = mode;
defaultColor = 999; // no defaultColor
}
public RouteOverlay(GeoPoint gp1,GeoPoint gp2,int mode, int defaultColor) {
this.gp1 = gp1;
this.gp2 = gp2;
this.mode = mode;
this.defaultColor = defaultColor;
}
public void setText(String t) {
this.text = t;
}
public void setBitmap(Bitmap bitmap) {
this.img = bitmap;
}
public int getMode() {
return mode;
}
#Override
public boolean draw (Canvas canvas, MapView mapView, boolean shadow, long when) {
Projection projection = mapView.getProjection();
if (shadow == false) {
Paint paint = new Paint();
paint.setAntiAlias(true);
Point point = new Point();
projection.toPixels(gp1, point);
// mode=1:start
if(mode==1) {
if(defaultColor==999)
paint.setColor(Color.BLACK); // Color.BLUE
else
paint.setColor(defaultColor);
RectF oval=new RectF(point.x - mRadius, point.y - mRadius,
point.x + mRadius, point.y + mRadius);
// start point
canvas.drawOval(oval, paint);
}
// mode=2:path
else if(mode==2) {
if(defaultColor==999)
paint.setColor(Color.RED);
else
paint.setColor(defaultColor);
Point point2 = new Point();
projection.toPixels(gp2, point2);
paint.setStrokeWidth(5);
paint.setAlpha(defaultColor==Color.parseColor("#6C8715")?220:120);
canvas.drawLine(point.x, point.y, point2.x,point2.y, paint);
}
/* mode=3:end */
else if(mode==3) {
/* the last path */
if(defaultColor==999)
paint.setColor(Color.BLACK); // Color.GREEN
else
paint.setColor(defaultColor);
Point point2 = new Point();
projection.toPixels(gp2, point2);
paint.setStrokeWidth(5);
paint.setAlpha(defaultColor==Color.parseColor("#6C8715")?220:120);
canvas.drawLine(point.x, point.y, point2.x,point2.y, paint);
RectF oval=new RectF(point2.x - mRadius,point2.y - mRadius,
point2.x + mRadius,point2.y + mRadius);
/* end point */
paint.setAlpha(255);
canvas.drawOval(oval, paint);
}
}
return super.draw(canvas, mapView, shadow, when);
}
}
Thank Mathias Lin, tested and it works!
In addition, sample implementation of Mathias's method in activity can be as follows.
public class DirectionMapActivity extends MapActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.directionmap);
MapView mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
// Acquire a reference to the system Location Manager
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
String locationProvider = LocationManager.NETWORK_PROVIDER;
Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);
StringBuilder urlString = new StringBuilder();
urlString.append("http://maps.google.com/maps?f=d&hl=en");
urlString.append("&saddr=");//from
urlString.append( Double.toString(lastKnownLocation.getLatitude() ));
urlString.append(",");
urlString.append( Double.toString(lastKnownLocation.getLongitude() ));
urlString.append("&daddr=");//to
urlString.append( Double.toString((double)dest[0]/1.0E6 ));
urlString.append(",");
urlString.append( Double.toString((double)dest[1]/1.0E6 ));
urlString.append("&ie=UTF8&0&om=0&output=kml");
try{
// setup the url
URL url = new URL(urlString.toString());
// create the factory
SAXParserFactory factory = SAXParserFactory.newInstance();
// create a parser
SAXParser parser = factory.newSAXParser();
// create the reader (scanner)
XMLReader xmlreader = parser.getXMLReader();
// instantiate our handler
NavigationSaxHandler navSaxHandler = new NavigationSaxHandler();
// assign our handler
xmlreader.setContentHandler(navSaxHandler);
// get our data via the url class
InputSource is = new InputSource(url.openStream());
// perform the synchronous parse
xmlreader.parse(is);
// get the results - should be a fully populated RSSFeed instance, or null on error
NavigationDataSet ds = navSaxHandler.getParsedData();
// draw path
drawPath(ds, Color.parseColor("#add331"), mapView );
// find boundary by using itemized overlay
GeoPoint destPoint = new GeoPoint(dest[0],dest[1]);
GeoPoint currentPoint = new GeoPoint( new Double(lastKnownLocation.getLatitude()*1E6).intValue()
,new Double(lastKnownLocation.getLongitude()*1E6).intValue() );
Drawable dot = this.getResources().getDrawable(R.drawable.pixel);
MapItemizedOverlay bgItemizedOverlay = new MapItemizedOverlay(dot,this);
OverlayItem currentPixel = new OverlayItem(destPoint, null, null );
OverlayItem destPixel = new OverlayItem(currentPoint, null, null );
bgItemizedOverlay.addOverlay(currentPixel);
bgItemizedOverlay.addOverlay(destPixel);
// center and zoom in the map
MapController mc = mapView.getController();
mc.zoomToSpan(bgItemizedOverlay.getLatSpanE6()*2,bgItemizedOverlay.getLonSpanE6()*2);
mc.animateTo(new GeoPoint(
(currentPoint.getLatitudeE6() + destPoint.getLatitudeE6()) / 2
, (currentPoint.getLongitudeE6() + destPoint.getLongitudeE6()) / 2));
} catch(Exception e) {
Log.d("DirectionMap","Exception parsing kml.");
}
}
// and the rest of the methods in activity, e.g. drawPath() etc...
MapItemizedOverlay.java
public class MapItemizedOverlay extends ItemizedOverlay{
private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
private Context mContext;
public MapItemizedOverlay(Drawable defaultMarker, Context context) {
super(boundCenterBottom(defaultMarker));
mContext = context;
}
public void addOverlay(OverlayItem overlay) {
mOverlays.add(overlay);
populate();
}
#Override
protected OverlayItem createItem(int i) {
return mOverlays.get(i);
}
#Override
public int size() {
return mOverlays.size();
}
}
There is now a beta available of Google Maps KML Importing Utility.
It is part of the Google Maps Android API Utility Library. As documented it allows loading KML files from streams
KmlLayer layer = new KmlLayer(getMap(), kmlInputStream, getApplicationContext());
or local resources
KmlLayer layer = new KmlLayer(getMap(), R.raw.kmlFile, getApplicationContext());
After you have created a KmlLayer, call addLayerToMap() to add the imported data onto the map.
layer.addLayerToMap();
Mathias Lin code working beautifully. However, you might want to consider changing this part inside drawPath method:
if (lngLat.length >= 2 && gp1.getLatitudeE6() > 0 && gp1.getLongitudeE6() > 0
&& gp2.getLatitudeE6() > 0 && gp2.getLongitudeE6() > 0) {
GeoPoint can be less than zero as well, I switch mine to:
if (lngLat.length >= 2 && gp1.getLatitudeE6() != 0 && gp1.getLongitudeE6() != 0
&& gp2.getLatitudeE6() != 0 && gp2.getLongitudeE6() != 0) {
Thank you :D