/*
* Copyright 2014 Thomas Hoffmann
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.j4velin.mapsmeasure;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.util.Pair;
import android.util.TypedValue;
import com.google.android.gms.maps.model.LatLng;
import com.google.maps.android.PolyUtil;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
import java.util.WeakHashMap;
abstract class Util {
public static float lastElevation;
public static final String TAG_OPEN = "<elevation>";
public static final String TAG_CLOSE = "</elevation>";
public static final int ELEVATION_TRACE_SAMPLES = 20;
private final static WeakHashMap<LatLng, Float> CACHE = new WeakHashMap<>();
/**
* Returns the height of the status bar
* from http://mrtn.me/blog/2012/03/17/get-the-height-of-the-status-bar-in-android/
*
* @param c the Context
* @return the height of the status bar
*/
static int getStatusBarHeight(final Context c) {
int result = 0;
int resourceId = c.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = c.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
/**
* Returns the height of the navigation bar
*
* @param c the Context
* @return the height of the navigation bar
*/
static int getNavigationBarHeight(final Context c) {
int result = 0;
int resourceId =
c.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
result = c.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
/**
* Converts the given lenght in dp into pixels
*
* @param c the Context
* @param dp the size in dp
* @return the size in px
*/
static int dpToPx(final Context c, int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
c.getResources().getDisplayMetrics());
}
/**
* Writes the given trace of points to the given file in CSV format,
* separated by ";"
*
* @param f the file to write to
* @param trace the trace to write
* @throws IOException
*/
static void saveToFile(final File f, final Stack<LatLng> trace) throws IOException {
if (!f.exists()) f.createNewFile();
BufferedWriter out = new BufferedWriter(new FileWriter(f));
LatLng current;
for (int i = 0; i < trace.size(); i++) {
current = trace.get(i);
out.append(String.valueOf(current.latitude)).append(",")
.append(String.valueOf(current.longitude)).append("\n");
}
out.close();
}
/**
* Replaces the current points on the map with the one from the provided
* file
*
* @param f the file to read from
* @param m the Map activity to add the new points to
* @throws IOException
*/
static void loadFromFile(final Uri f, final Map m) throws IOException {
List<LatLng> list = new LinkedList<>();
BufferedReader in = new BufferedReader(
new InputStreamReader(m.getContentResolver().openInputStream(f)));
String line;
String[] data;
while ((line = in.readLine()) != null) {
data = line.split(",");
if (data.length != 2) data = line.split(";"); // try with semicolon instead
try {
list.add(new LatLng(Double.parseDouble(data[0]), Double.parseDouble(data[1])));
} catch (Exception nfe) {
nfe.printStackTrace();
}
}
in.close();
m.clear();
for (int i = 0; i < list.size(); i++) {
m.addPoint(list.get(i));
}
if (!list.isEmpty()) m.moveCamera(list.get(0));
}
/**
* Queries for a single elevation information
*
* @param loc the location
* @return a pair of 0's
*/
private static Pair<Float, Float> getSingleElevation(final LatLng loc) {
if (CACHE.containsKey(loc)) {
lastElevation = CACHE.get(loc);
} else {
HttpURLConnection urlConnection = null;
BufferedReader in = null;
try {
URL url = new URL("http://maps.googleapis.com/maps/api/elevation/xml?locations=" +
loc.latitude + "," + loc.longitude);
urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
String line;
int subStringStart = TAG_OPEN.length();
while ((line = in.readLine()) != null) {
if (line.trim().startsWith(TAG_OPEN)) {
lastElevation = Float.parseFloat(
line.substring(subStringStart + 2, line.indexOf(TAG_CLOSE)));
CACHE.put(loc, lastElevation);
if (BuildConfig.DEBUG) Logger.log("elevation read: " + line);
break;
}
}
} catch (IOException io) {
if (BuildConfig.DEBUG) Logger.log(io);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
if (BuildConfig.DEBUG) Logger.log(e);
}
}
if (urlConnection != null) urlConnection.disconnect();
}
}
return new Pair<>(0f, 0f);
}
/**
* Updates the elevations graph
*
* @param view the graph
* @param trace the points
* @return the aggregated up and down distances along the trace
*/
static Pair<Float, Float> updateElevationView(final ElevationView view,
final List<LatLng> trace) {
if (trace.isEmpty()) return new Pair<>(0f, 0f);
if (trace.size() == 1) return getSingleElevation(trace.get(0));
String encodedPath = PolyUtil.encode(trace);
float[] result = new float[ELEVATION_TRACE_SAMPLES];
HttpURLConnection urlConnection = null;
BufferedReader in = null;
try {
URL url = new URL("http://maps.googleapis.com/maps/api/elevation/xml?path=enc:" +
encodedPath + "&samples=" + ELEVATION_TRACE_SAMPLES);
urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
String line;
int pos = 0;
int subStringStart = TAG_OPEN.length();
while ((line = in.readLine()) != null) {
if (line.trim().startsWith(TAG_OPEN)) {
result[pos] = Float.parseFloat(
line.substring(subStringStart + 2, line.indexOf(TAG_CLOSE)));
pos++;
if (BuildConfig.DEBUG) Logger.log("elevation result: " + line);
}
}
} catch (IOException io) {
if (BuildConfig.DEBUG) Logger.log(io);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
if (BuildConfig.DEBUG) Logger.log(e);
}
}
if (urlConnection != null) urlConnection.disconnect();
}
view.setElevationData(result);
float up = 0, down = 0, difference;
for (int i = 1; i < result.length; i++) {
difference = result[i - 1] - result[i];
if (difference < 0) up += difference;
else down += difference;
}
lastElevation = result[result.length - 1];
return new Pair<>(up, down);
}
/**
* Tests for an internet connection.
*
* @param context the Context
* @return true, if connected to the internet
*/
static boolean checkInternetConnection(final Context context) {
final ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
// test for connection
return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isAvailable() &&
cm.getActiveNetworkInfo().isConnected();
}
}