Compare commits
70 commits
master
...
android_ht
Author | SHA1 | Date | |
---|---|---|---|
|
419edcac29 | ||
|
b5a24dc23b | ||
|
9a35b70773 | ||
|
31a3ec3b05 | ||
|
dcc05f7129 | ||
|
e070f5be94 | ||
|
b708f8e6ff | ||
|
65e8328a0c | ||
|
1d3849ef4d | ||
|
98f0823bbb | ||
|
ff236c7d81 | ||
|
d62a92b5e8 | ||
|
c914e18fc1 | ||
|
1b85b5a732 | ||
|
ad82cd419f | ||
|
9d37cff564 | ||
|
d0c6270a00 | ||
|
6c86997d2c | ||
|
2cd4e23463 | ||
|
576e70a606 | ||
|
ce2b0eacbf | ||
|
2851fd38cd | ||
|
463679afd3 | ||
|
ad444aadaf | ||
|
2442759d07 | ||
|
b779b8b61f | ||
|
f34b1fdf11 | ||
|
a92bac55f7 | ||
|
96653b3749 | ||
|
ee54d374ff | ||
|
2b9db97fb7 | ||
|
b3cb492558 | ||
|
08ab7a6613 | ||
|
150e769709 | ||
|
485ee88a13 | ||
|
aeff02d633 | ||
|
b4d4e79b6a | ||
|
cdde9f3960 | ||
|
23b871ee22 | ||
|
7ae7f45c48 | ||
|
cb9c141c64 | ||
|
9ed5eb95c7 | ||
|
aa1932e3d2 | ||
|
fbeba45ada | ||
|
9fc7d9ef26 | ||
|
96ad964beb | ||
|
920241a043 | ||
|
8505f67d68 | ||
|
8dd5bda3fc | ||
|
9112d4a34f | ||
|
edb3aede9e | ||
|
a7633b2031 | ||
|
fef6f93621 | ||
|
9823461435 | ||
|
d1451e9889 | ||
|
c436b1dcb8 | ||
|
b846969e49 | ||
|
2f1707167c | ||
|
656a316f87 | ||
|
c81e5a88ae | ||
|
2869cae3a0 | ||
|
1f8dbb7694 | ||
|
71c895c81e | ||
|
40bc660320 | ||
|
c0c07b95c2 | ||
|
065755d5b2 | ||
|
8f4b8c8349 | ||
|
3ad4e5fc71 | ||
|
409aa0574a | ||
|
c2395016f9 |
22 changed files with 4689 additions and 24 deletions
|
@ -8,6 +8,7 @@ public interface OsmAndCustomizationConstants {
|
|||
String DRAWER_MAP_MARKERS_ID = DRAWER_ITEM_ID_SCHEME + "map_markers";
|
||||
String DRAWER_MY_PLACES_ID = DRAWER_ITEM_ID_SCHEME + "my_places";
|
||||
String DRAWER_SEARCH_ID = DRAWER_ITEM_ID_SCHEME + "search";
|
||||
String DRAWER_WEBSERVER_ID = DRAWER_ITEM_ID_SCHEME + "server";
|
||||
String DRAWER_DIRECTIONS_ID = DRAWER_ITEM_ID_SCHEME + "directions";
|
||||
String DRAWER_CONFIGURE_MAP_ID = DRAWER_ITEM_ID_SCHEME + "configure_map";
|
||||
String DRAWER_DOWNLOAD_MAPS_ID = DRAWER_ITEM_ID_SCHEME + "download_maps";
|
||||
|
|
3322
OsmAnd/assets/server/css/site.css
Normal file
3322
OsmAnd/assets/server/css/site.css
Normal file
File diff suppressed because it is too large
Load diff
BIN
OsmAnd/assets/server/images/logo-grey.png
Normal file
BIN
OsmAnd/assets/server/images/logo-grey.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
81
OsmAnd/assets/server/index.html
Normal file
81
OsmAnd/assets/server/index.html
Normal file
|
@ -0,0 +1,81 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="cache-control" content="max-age=0"/>
|
||||
<meta http-equiv="cache-control" content="no-cache"/>
|
||||
<meta http-equiv="expires" content="0"/>
|
||||
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT"/>
|
||||
<meta http-equiv="pragma" content="no-cache"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>OsmAnd - Offline Mobile Maps and Navigation</title>
|
||||
<link rel="stylesheet" type="text/css" href="/css/site.css?v=4"/>
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.1.0/dist/leaflet.css"/>
|
||||
<script src="https://unpkg.com/leaflet@1.1.0/dist/leaflet.js"></script>
|
||||
<script type="text/javascript" src="/scripts/jquery-3.1.0.min.js"></script>
|
||||
<script src="/scripts/leaflet.awesome-markers.js"></script>
|
||||
<link rel="stylesheet" href="http://code.ionicframework.com/ionicons/1.5.2/css/ionicons.min.css">
|
||||
|
||||
<script type="text/javascript" src="/scripts/go.js?v=5"></script>
|
||||
|
||||
<script>
|
||||
function getMarkerContent(feature) {
|
||||
var p = feature.properties;
|
||||
var popupContent = p.title;
|
||||
if (p.opr_id) {
|
||||
popupContent += " (" + p.opr_id + ") ";
|
||||
}
|
||||
if (p.tags) {
|
||||
for (var t in p.tags) {
|
||||
popupContent += "<br>" + t + " " + p.tags[t];
|
||||
}
|
||||
}
|
||||
if (p.opr_id) {
|
||||
popupContent += "<br><a href=\'/api/admin?view=objects&browse=type&type=opr.place&subtype=id&key=" +
|
||||
p.opr_id + "\'>OpenPlaceReviews</a>";
|
||||
}
|
||||
if (p.osm_id) {
|
||||
popupContent += "<br><a href=\'https://www.openstreetmap.org/" +
|
||||
p.osm_type + "/" + p.osm_id + "\'>OpenStreetMap</a>";
|
||||
}
|
||||
return popupContent;
|
||||
}
|
||||
|
||||
function markerClick(e) {
|
||||
|
||||
}
|
||||
|
||||
function setupMarkers() {
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: "/favorites",
|
||||
async: false,
|
||||
contentType: "application/json",
|
||||
dataType: 'json',
|
||||
complete: function (r) {
|
||||
var points = JSON.parse(r.responseText);
|
||||
points.forEach(e => {
|
||||
window.goMap.map.addPopupMarker(e, markerClick);
|
||||
});
|
||||
},
|
||||
error: function (e) {
|
||||
alert("Error happened while getting favourite points " + e.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// $(document).ready(function () {
|
||||
// //setupMarkers();
|
||||
// });
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="gocontainer" id="gocontainer">
|
||||
<div class="goheader">
|
||||
<a href="/"><img src="/images/logo-grey.png" class="logo"/></a>
|
||||
</div>
|
||||
<div id="map"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
273
OsmAnd/assets/server/scripts/go.js
Normal file
273
OsmAnd/assets/server/scripts/go.js
Normal file
|
@ -0,0 +1,273 @@
|
|||
var requestUtils={
|
||||
'getParamValue':function(paramName){
|
||||
let value= (location.search.split(paramName + '=')[1]||'').split('&')[0];
|
||||
if (value && value.length > 0){
|
||||
return value;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
'isIOS':function(){
|
||||
return /(iPad|iPhone|iPod)/g.test( navigator.userAgent );
|
||||
},
|
||||
'redirect':function(newUrl){
|
||||
document.location = newUrl;
|
||||
}
|
||||
};
|
||||
|
||||
var goMap = {
|
||||
'config':{
|
||||
'containerid': 'gocontainer',
|
||||
'defaults':{
|
||||
'lat':50.27,
|
||||
'lon':30.30,
|
||||
'zoom':13
|
||||
}
|
||||
},
|
||||
'utils':{
|
||||
'getPointFromUrl':function(){
|
||||
let point = {};
|
||||
point.lat = requestUtils.getParamValue('lat');
|
||||
point.lon = requestUtils.getParamValue('lon');
|
||||
point.zoom = requestUtils.getParamValue('z');
|
||||
return point;
|
||||
},
|
||||
'isPointComplete':function(point){
|
||||
if (!point.lat || !point.lon){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
'extendPoint':function(initialPoint, newPoint){
|
||||
let point={};
|
||||
point.lat=newPoint.lat;
|
||||
if (!point.lat || point.lat == null){
|
||||
point.lat = initialPoint.lat;
|
||||
}
|
||||
point.lon=newPoint.lon;
|
||||
if (!point.lon || point.lon == null){
|
||||
point.lon = initialPoint.lon;
|
||||
}
|
||||
point.zoom=newPoint.zoom;
|
||||
if (!point.zoom || point.zoom == null){
|
||||
point.zoom = initialPoint.zoom;
|
||||
}
|
||||
return point;
|
||||
}
|
||||
},
|
||||
'init': function(config){
|
||||
if (config && typeof (config) == 'object') {
|
||||
$.extend(goMap.config, config);
|
||||
}
|
||||
goMap.$container = $('#' + goMap.config.containerid);
|
||||
goMap.$footer = goMap.$container.find('.gofooter');
|
||||
goMap.$latitude = goMap.$container.find('.latitude');
|
||||
goMap.$longitude = goMap.$container.find('.longitude');
|
||||
|
||||
let inputPoint = goMap.utils.getPointFromUrl();
|
||||
goMap.point = goMap.utils.extendPoint(goMap.config.defaults, inputPoint);
|
||||
goMap.refreshCoordinates();
|
||||
|
||||
goMap.map =$.mapwidget();
|
||||
goMap.map.showPoint(goMap.point);
|
||||
|
||||
let inputComplete = goMap.utils.isPointComplete(inputPoint);
|
||||
if (inputComplete){
|
||||
goMap.map.addMarker(goMap.point);
|
||||
}
|
||||
goMap.point = goMap.utils.getPointFromUrl();
|
||||
},
|
||||
'refreshCoordinates':function(){
|
||||
goMap.$latitude.text(goMap.point.lat);
|
||||
goMap.$longitude.text(goMap.point.lon);
|
||||
}
|
||||
};
|
||||
|
||||
function toColor(num) {
|
||||
num >>>= 0;
|
||||
var b = num & 0xFF,
|
||||
g = (num & 0xFF00) >>> 8,
|
||||
r = (num & 0xFF0000) >>> 16,
|
||||
a = ( (num & 0xFF000000) >>> 24 ) / 255 ;
|
||||
return "rgba(" + [r, g, b, a].join(",") + ")";
|
||||
}
|
||||
|
||||
(function($) {
|
||||
$.mapwidget = function(config) {
|
||||
var loc = goMap.point.lat + '/' + goMap.point.lon;
|
||||
var lparams = '?mlat='+goMap.point.lat + '&mlon=' + goMap.point.lon;
|
||||
var mapobj={
|
||||
config: $.extend({
|
||||
'mapid':'map',
|
||||
'maxzoom':20,
|
||||
'maxnativezoom':19,
|
||||
'sourceurl': window.location.protocol + "//" + window.location.host + '/tile/{z}/{x}/{y}.png',
|
||||
'attribution':'© <a href="https://www.openstreetmap.org/'+lparams+'#map=15/'+loc+'">OpenStreetMap</a> contributors'
|
||||
}, config),
|
||||
init:function(){
|
||||
mapobj.map = L.map(mapobj.config.mapid);
|
||||
L.tileLayer(mapobj.config.sourceurl, {
|
||||
attribution: mapobj.config.attribution,
|
||||
maxZoom: mapobj.config.maxzoom,
|
||||
maxNativeZoom: mapobj.config.maxnativezoom
|
||||
}).addTo(mapobj.map);
|
||||
},
|
||||
showPoint:function(point){
|
||||
mapobj.map.setView([point.lat, point.lon], point.zoom);
|
||||
},
|
||||
addMarker:function(point){
|
||||
L.marker([point.lat, point.lon]).addTo(mapobj.map);
|
||||
},
|
||||
addPopupMarker:function(favorite,onClickEvent){
|
||||
window.point = favorite;
|
||||
var point = {};
|
||||
point.lat = favorite.latitude;
|
||||
point.lon = favorite.longitude;
|
||||
var popup = L.popup().setContent(
|
||||
"name: <b>" + favorite.name + "</b><br/>" +
|
||||
"address: <i>" + favorite.address + "</i><br/>"
|
||||
+ "category: " + favorite.category);
|
||||
var customMarker = L.AwesomeMarkers.icon({
|
||||
icon: 'home',
|
||||
markerColor: toColor(favorite.color),
|
||||
iconColor: toColor(favorite.color)
|
||||
});
|
||||
L.marker([point.lat, point.lon],{icon: customMarker})
|
||||
.bindPopup(popup)
|
||||
.addTo(mapobj.map)
|
||||
.on('click', function(e) {
|
||||
onClickEvent(e);
|
||||
});
|
||||
}
|
||||
};
|
||||
mapobj.init();
|
||||
return {
|
||||
showPoint: mapobj.showPoint,
|
||||
addMarker: mapobj.addMarker,
|
||||
addPopupMarker: mapobj.addPopupMarker
|
||||
};
|
||||
};
|
||||
})(jQuery);
|
||||
|
||||
(function($) {
|
||||
$.timer=function(config){
|
||||
var timerobj={
|
||||
config: $.extend({
|
||||
'timeoutInMs':300,
|
||||
'maxActionDelayInMs':2000,
|
||||
'action':function(){},
|
||||
'actionparams':null
|
||||
}, config),
|
||||
init:function(){
|
||||
timerobj.timer = null;
|
||||
timerobj.startDate = null;
|
||||
},
|
||||
start:function(){
|
||||
timerobj.cancel();
|
||||
timerobj.startDate = new Date();
|
||||
timerobj.timer=setTimeout(timerobj.onTimer, timerobj.config.timeoutInMs);
|
||||
},
|
||||
cancel:function(){
|
||||
if (timerobj.timer != null){
|
||||
clearTimeout(timerobj.timer);
|
||||
timerobj.timer = null;
|
||||
timerobj.startDate = null;
|
||||
}
|
||||
},
|
||||
onTimer:function(){
|
||||
timerobj.timer= null;
|
||||
let now = new Date();
|
||||
if(now - timerobj.startDate < timerobj.config.maxActionDelayInMs){
|
||||
timerobj.config.action(timerobj.config.actionparams);
|
||||
}
|
||||
}
|
||||
};
|
||||
timerobj.init();
|
||||
return {
|
||||
start:timerobj.start,
|
||||
cancel:timerobj.cancel
|
||||
};
|
||||
};
|
||||
})(jQuery);
|
||||
|
||||
var iosAppRedirect = {
|
||||
config:{
|
||||
appPrefix:'osmandmaps://',
|
||||
containerid:'gocontainer',
|
||||
cookieName:'OsmAndInstalled',
|
||||
cookieNoExpirationTimeoutInDays:30
|
||||
},
|
||||
init:function(config){
|
||||
if (config && typeof (config) == 'object') {
|
||||
$.extend(iosAppRedirect.config, config);
|
||||
}
|
||||
|
||||
if (!requestUtils.isIOS()){
|
||||
return;
|
||||
}
|
||||
iosAppRedirect.$container = $('#' + iosAppRedirect.config.containerid);
|
||||
iosAppRedirect.$overlay = iosAppRedirect.$container.find('.overlay');
|
||||
iosAppRedirect.$popup = iosAppRedirect.$container.find('.popup');
|
||||
iosAppRedirect.$yesBtn = iosAppRedirect.$container.find('.yes');
|
||||
iosAppRedirect.$noBtn = iosAppRedirect.$container.find('.no');
|
||||
iosAppRedirect.$cancelBtn = iosAppRedirect.$container.find('.cancel');
|
||||
iosAppRedirect.applestorelink = iosAppRedirect.$container.find('.gobadges .apple a').attr('href');
|
||||
iosAppRedirect.applink = iosAppRedirect.config.appPrefix + document.location.search;
|
||||
|
||||
|
||||
if (iosAppRedirect.isAppInstalled() === "yes"){
|
||||
iosAppRedirect.redirectToApp();
|
||||
return;
|
||||
}
|
||||
if (iosAppRedirect.isAppInstalled() === "no"){
|
||||
return;
|
||||
}
|
||||
|
||||
iosAppRedirect.$yesBtn.on('click', function(){
|
||||
iosAppRedirect.redirectToApp();
|
||||
iosAppRedirect.closePopup();
|
||||
});
|
||||
|
||||
iosAppRedirect.$noBtn.on('click', function(){
|
||||
iosAppRedirect.setCookie(true);
|
||||
iosAppRedirect.closePopup();
|
||||
window.open(iosAppRedirect.applestorelink , '_blank');
|
||||
});
|
||||
|
||||
iosAppRedirect.$cancelBtn.on('click', function(){
|
||||
iosAppRedirect.setCookie(false);
|
||||
iosAppRedirect.closePopup();
|
||||
});
|
||||
iosAppRedirect.openPopup();
|
||||
},
|
||||
isAppInstalled:function(){
|
||||
return Cookies.get('OsmAndInstalled');
|
||||
},
|
||||
redirectToApp:function(){
|
||||
iosAppRedirect.timer = $.timer({action:iosAppRedirect.clearCookie});
|
||||
iosAppRedirect.timer.start();
|
||||
requestUtils.redirect(iosAppRedirect.applink);
|
||||
},
|
||||
setCookie:function(appInstalled){
|
||||
if (appInstalled === true){
|
||||
Cookies.set(iosAppRedirect.config.cookieName, "yes");
|
||||
}else{
|
||||
Cookies.set(iosAppRedirect.config.cookieName, "no", { expires: iosAppRedirect.config.cookieNoExpirationTimeoutInDays });
|
||||
}
|
||||
},
|
||||
clearCookie:function(){
|
||||
Cookies.remove('OsmAndInstalled');
|
||||
},
|
||||
openPopup:function(){
|
||||
iosAppRedirect.$overlay.show();
|
||||
iosAppRedirect.$popup.show();
|
||||
},
|
||||
closePopup:function(){
|
||||
iosAppRedirect.$overlay.hide();
|
||||
iosAppRedirect.$popup.hide();
|
||||
}
|
||||
};
|
||||
|
||||
$( document ).ready(function() {
|
||||
goMap.init();
|
||||
iosAppRedirect.init();
|
||||
});
|
4
OsmAnd/assets/server/scripts/jquery-3.1.0.min.js
vendored
Normal file
4
OsmAnd/assets/server/scripts/jquery-3.1.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
165
OsmAnd/assets/server/scripts/js.cookie.js
Normal file
165
OsmAnd/assets/server/scripts/js.cookie.js
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*!
|
||||
* JavaScript Cookie v2.1.4
|
||||
* https://github.com/js-cookie/js-cookie
|
||||
*
|
||||
* Copyright 2006, 2015 Klaus Hartl & Fagner Brack
|
||||
* Released under the MIT license
|
||||
*/
|
||||
;(function (factory) {
|
||||
var registeredInModuleLoader = false;
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(factory);
|
||||
registeredInModuleLoader = true;
|
||||
}
|
||||
if (typeof exports === 'object') {
|
||||
module.exports = factory();
|
||||
registeredInModuleLoader = true;
|
||||
}
|
||||
if (!registeredInModuleLoader) {
|
||||
var OldCookies = window.Cookies;
|
||||
var api = window.Cookies = factory();
|
||||
api.noConflict = function () {
|
||||
window.Cookies = OldCookies;
|
||||
return api;
|
||||
};
|
||||
}
|
||||
}(function () {
|
||||
function extend () {
|
||||
var i = 0;
|
||||
var result = {};
|
||||
for (; i < arguments.length; i++) {
|
||||
var attributes = arguments[ i ];
|
||||
for (var key in attributes) {
|
||||
result[key] = attributes[key];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function init (converter) {
|
||||
function api (key, value, attributes) {
|
||||
var result;
|
||||
if (typeof document === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Write
|
||||
|
||||
if (arguments.length > 1) {
|
||||
attributes = extend({
|
||||
path: '/'
|
||||
}, api.defaults, attributes);
|
||||
|
||||
if (typeof attributes.expires === 'number') {
|
||||
var expires = new Date();
|
||||
expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
|
||||
attributes.expires = expires;
|
||||
}
|
||||
|
||||
// We're using "expires" because "max-age" is not supported by IE
|
||||
attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
|
||||
|
||||
try {
|
||||
result = JSON.stringify(value);
|
||||
if (/^[\{\[]/.test(result)) {
|
||||
value = result;
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
if (!converter.write) {
|
||||
value = encodeURIComponent(String(value))
|
||||
.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
|
||||
} else {
|
||||
value = converter.write(value, key);
|
||||
}
|
||||
|
||||
key = encodeURIComponent(String(key));
|
||||
key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
|
||||
key = key.replace(/[\(\)]/g, escape);
|
||||
|
||||
var stringifiedAttributes = '';
|
||||
|
||||
for (var attributeName in attributes) {
|
||||
if (!attributes[attributeName]) {
|
||||
continue;
|
||||
}
|
||||
stringifiedAttributes += '; ' + attributeName;
|
||||
if (attributes[attributeName] === true) {
|
||||
continue;
|
||||
}
|
||||
stringifiedAttributes += '=' + attributes[attributeName];
|
||||
}
|
||||
return (document.cookie = key + '=' + value + stringifiedAttributes);
|
||||
}
|
||||
|
||||
// Read
|
||||
|
||||
if (!key) {
|
||||
result = {};
|
||||
}
|
||||
|
||||
// To prevent the for loop in the first place assign an empty array
|
||||
// in case there are no cookies at all. Also prevents odd result when
|
||||
// calling "get()"
|
||||
var cookies = document.cookie ? document.cookie.split('; ') : [];
|
||||
var rdecode = /(%[0-9A-Z]{2})+/g;
|
||||
var i = 0;
|
||||
|
||||
for (; i < cookies.length; i++) {
|
||||
var parts = cookies[i].split('=');
|
||||
var cookie = parts.slice(1).join('=');
|
||||
|
||||
if (cookie.charAt(0) === '"') {
|
||||
cookie = cookie.slice(1, -1);
|
||||
}
|
||||
|
||||
try {
|
||||
var name = parts[0].replace(rdecode, decodeURIComponent);
|
||||
cookie = converter.read ?
|
||||
converter.read(cookie, name) : converter(cookie, name) ||
|
||||
cookie.replace(rdecode, decodeURIComponent);
|
||||
|
||||
if (this.json) {
|
||||
try {
|
||||
cookie = JSON.parse(cookie);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (key === name) {
|
||||
result = cookie;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
result[name] = cookie;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
api.set = api;
|
||||
api.get = function (key) {
|
||||
return api.call(api, key);
|
||||
};
|
||||
api.getJSON = function () {
|
||||
return api.apply({
|
||||
json: true
|
||||
}, [].slice.call(arguments));
|
||||
};
|
||||
api.defaults = {};
|
||||
|
||||
api.remove = function (key, attributes) {
|
||||
api(key, '', extend(attributes, {
|
||||
expires: -1
|
||||
}));
|
||||
};
|
||||
|
||||
api.withConverter = init;
|
||||
|
||||
return api;
|
||||
}
|
||||
|
||||
return init(function () {});
|
||||
}));
|
134
OsmAnd/assets/server/scripts/leaflet.awesome-markers.js
Normal file
134
OsmAnd/assets/server/scripts/leaflet.awesome-markers.js
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
Leaflet.AwesomeMarkers, a plugin that adds colorful iconic markers for Leaflet, based on the Font Awesome icons
|
||||
(c) 2012-2013, Lennard Voogdt
|
||||
|
||||
http://leafletjs.com
|
||||
https://github.com/lvoogdt
|
||||
*/
|
||||
|
||||
/*global L*/
|
||||
|
||||
(function (window, document, undefined) {
|
||||
"use strict";
|
||||
/*
|
||||
* Leaflet.AwesomeMarkers assumes that you have already included the Leaflet library.
|
||||
*/
|
||||
|
||||
L.AwesomeMarkers = {};
|
||||
|
||||
L.AwesomeMarkers.version = '2.0.1';
|
||||
|
||||
L.AwesomeMarkers.Icon = L.Icon.extend({
|
||||
options: {
|
||||
shadowAnchor: [10, 12],
|
||||
shadowSize: [36, 16],
|
||||
className: 'awesome-marker',
|
||||
icon: 'block',
|
||||
markerColor: 'white',
|
||||
iconColor: 'white'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
options = L.Util.setOptions(this, options);
|
||||
},
|
||||
|
||||
createIcon: function () {
|
||||
var options = L.Util.setOptions(this);
|
||||
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
var path = document.createElementNS('http://www.w3.org/2000/svg', "path");
|
||||
var backgroundCircle = document.createElementNS('http://www.w3.org/2000/svg', "circle");
|
||||
var icongroup = document.createElementNS('http://www.w3.org/2000/svg', "g");
|
||||
var icon = document.createElementNS('http://www.w3.org/2000/svg', "text");
|
||||
|
||||
svg.setAttribute('width', '31');
|
||||
svg.setAttribute('height', '42');
|
||||
svg.setAttribute('class', 'awesome-marker');
|
||||
svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink");
|
||||
|
||||
backgroundCircle.setAttribute('cx', '15.5');
|
||||
backgroundCircle.setAttribute('cy', '15');
|
||||
backgroundCircle.setAttribute('r', '11');
|
||||
backgroundCircle.setAttribute('fill', options.markerColor);
|
||||
|
||||
path.setAttributeNS(null, "d", "M15.6,1c-7.7,0-14,6.3-14,14c0,10.5,14,26,14,26s14-15.5,14-26C29.6,7.3,23.3,1,15.6,1z");
|
||||
//path.setAttribute('class', 'awesome-marker-background');
|
||||
path.setAttribute('stroke', 'white');
|
||||
path.setAttribute('style', 'fill:' + options.markerColor)
|
||||
|
||||
icon.textContent = options.icon;
|
||||
icon.setAttribute('x', '7');
|
||||
icon.setAttribute('y', '23');
|
||||
icon.setAttribute('class', 'material-icons');
|
||||
icon.setAttribute('fill', options.iconColor);
|
||||
icon.setAttribute('font-family', 'Material Icons');
|
||||
|
||||
svg.appendChild(path);
|
||||
svg.appendChild(backgroundCircle);
|
||||
icongroup.appendChild(icon);
|
||||
svg.appendChild(icongroup);
|
||||
|
||||
return svg;
|
||||
},
|
||||
|
||||
_createInner: function() {
|
||||
var iconClass, iconSpinClass = "", iconColorClass = "", iconColorStyle = "", options = this.options;
|
||||
|
||||
if (options.spin && typeof options.spinClass === "string") {
|
||||
iconSpinClass = options.spinClass;
|
||||
}
|
||||
|
||||
if (options.iconColor) {
|
||||
if (options.iconColor === 'white' || options.iconColor === 'black') {
|
||||
iconColorClass = "icon-" + options.iconColor;
|
||||
} else {
|
||||
iconColorStyle = "style='color: " + options.iconColor + "' ";
|
||||
}
|
||||
}
|
||||
//return "<i " + iconColorStyle + "class='" + options.extraClasses + " " + options.prefix + " " + iconClass + " " + iconSpinClass + " " + iconColorClass + "'></i>"
|
||||
return options.extraClasses + " " + iconClass + " " + iconSpinClass + " " + iconColorClass;
|
||||
},
|
||||
|
||||
_setIconStyles: function (img, name) {
|
||||
var options = this.options,
|
||||
size = L.point(options[name === 'shadow' ? 'shadowSize' : 'iconSize']),
|
||||
anchor;
|
||||
|
||||
if (name === 'shadow') {
|
||||
anchor = L.point(options.shadowAnchor || options.iconAnchor);
|
||||
} else {
|
||||
anchor = L.point(options.iconAnchor);
|
||||
}
|
||||
|
||||
if (!anchor && size) {
|
||||
anchor = size.divideBy(2, true);
|
||||
}
|
||||
|
||||
img.className = 'awesome-marker-' + name + ' ' + options.className;
|
||||
|
||||
if (anchor) {
|
||||
img.style.marginLeft = (-anchor.x) + 'px';
|
||||
img.style.marginTop = (-anchor.y) + 'px';
|
||||
}
|
||||
|
||||
if (size) {
|
||||
img.style.width = size.x + 'px';
|
||||
img.style.height = size.y + 'px';
|
||||
}
|
||||
},
|
||||
|
||||
createShadow: function () {
|
||||
var div = document.createElement('div');
|
||||
|
||||
this._setIconStyles(div, 'shadow');
|
||||
return div;
|
||||
}
|
||||
});
|
||||
|
||||
L.AwesomeMarkers.icon = function (options) {
|
||||
return new L.AwesomeMarkers.Icon(options);
|
||||
};
|
||||
|
||||
}(this, document));
|
||||
|
||||
|
||||
|
7
OsmAnd/assets/server/scripts/leaflet.awesome-markers.min.js
vendored
Normal file
7
OsmAnd/assets/server/scripts/leaflet.awesome-markers.min.js
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
Leaflet.AwesomeMarkers, a plugin that adds colorful iconic markers for Leaflet, based on the Font Awesome icons
|
||||
(c) 2012-2013, Lennard Voogdt
|
||||
|
||||
http://leafletjs.com
|
||||
https://github.com/lvoogdt
|
||||
*//*global L*/(function(e,t,n){"use strict";L.AwesomeMarkers={};L.AwesomeMarkers.version="2.0.1";L.AwesomeMarkers.Icon=L.Icon.extend({options:{iconSize:[35,45],iconAnchor:[17,42],popupAnchor:[1,-32],shadowAnchor:[10,12],shadowSize:[36,16],className:"awesome-marker",prefix:"glyphicon",spinClass:"fa-spin",icon:"home",markerColor:"blue",iconColor:"white"},initialize:function(e){e=L.Util.setOptions(this,e)},createIcon:function(){var e=t.createElement("div"),n=this.options;n.icon&&(e.innerHTML=this._createInner());n.bgPos&&(e.style.backgroundPosition=-n.bgPos.x+"px "+ -n.bgPos.y+"px");this._setIconStyles(e,"icon-"+n.markerColor);return e},_createInner:function(){var e,t="",n="",r="",i=this.options;i.icon.slice(0,i.prefix.length+1)===i.prefix+"-"?e=i.icon:e=i.prefix+"-"+i.icon;i.spin&&typeof i.spinClass=="string"&&(t=i.spinClass);i.iconColor&&(i.iconColor==="white"||i.iconColor==="black"?n="icon-"+i.iconColor:r="style='color: "+i.iconColor+"' ");return"<i "+r+"class='"+i.prefix+" "+e+" "+t+" "+n+"'></i>"},_setIconStyles:function(e,t){var n=this.options,r=L.point(n[t==="shadow"?"shadowSize":"iconSize"]),i;t==="shadow"?i=L.point(n.shadowAnchor||n.iconAnchor):i=L.point(n.iconAnchor);!i&&r&&(i=r.divideBy(2,!0));e.className="awesome-marker-"+t+" "+n.className;if(i){e.style.marginLeft=-i.x+"px";e.style.marginTop=-i.y+"px"}if(r){e.style.width=r.x+"px";e.style.height=r.y+"px"}},createShadow:function(){var e=t.createElement("div");this._setIconStyles(e,"shadow");return e}});L.AwesomeMarkers.icon=function(e){return new L.AwesomeMarkers.Icon(e)}})(this,document);
|
|
@ -544,6 +544,7 @@ dependencies {
|
|||
implementation 'me.zhanghai.android.materialprogressbar:library:1.4.2'
|
||||
// JS core
|
||||
implementation group: 'org.mozilla', name: 'rhino', version: '1.7.9'
|
||||
implementation 'org.nanohttpd:nanohttpd:2.2.0'
|
||||
// size restrictions
|
||||
// implementation 'com.ibm.icu:icu4j:50.1'
|
||||
// implementation 'net.sf.trove4j:trove4j:3.0.3'
|
||||
|
|
34
OsmAnd/res/layout/server_fragment.xml
Normal file
34
OsmAnd/res/layout/server_fragment.xml
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="32dp"
|
||||
android:gravity="center"
|
||||
android:clickable="true"
|
||||
android:background="@color/color_black"
|
||||
android:focusable="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/server_status_textview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="center"
|
||||
android:autoLink="web"
|
||||
android:textColor="@color/color_white"
|
||||
android:text="@string/start_web_server"
|
||||
android:gravity="center_horizontal"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/server_start_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/shared_string_start"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/server_stop_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/shared_string_stop"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -11,6 +11,11 @@
|
|||
Thx - Hardy
|
||||
|
||||
-->
|
||||
<string name="shared_string_stop">Stop</string>
|
||||
<string name="shared_string_start">Start</string>
|
||||
<string name="start_web_server">Start web server</string>
|
||||
<string name="stop_web_server">Stop web server</string>
|
||||
<string name="web_server">Web server</string>
|
||||
<string name="shared_string_redo">Redo</string>
|
||||
<string name="one_point_error">Please add at least two points.</string>
|
||||
<string name="shared_string_is_saved">is saved</string>
|
||||
|
|
|
@ -232,7 +232,9 @@ public class MapViewTrackingUtilities implements OsmAndLocationListener, IMapLoc
|
|||
switchToRoutePlanningMode();
|
||||
}
|
||||
// When location is changed we need to refresh map in order to show movement!
|
||||
mapView.refreshMap();
|
||||
if (!mapView.isScreenViewDetached()){
|
||||
mapView.refreshMap();
|
||||
}
|
||||
}
|
||||
|
||||
if (dashboard != null) {
|
||||
|
|
|
@ -3,8 +3,11 @@ package net.osmand.plus.development;
|
|||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import net.osmand.plus.ContextMenuAdapter;
|
||||
import net.osmand.plus.ContextMenuItem;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
|
@ -14,6 +17,8 @@ import net.osmand.plus.Version;
|
|||
import net.osmand.plus.activities.ContributionVersionActivity;
|
||||
import net.osmand.plus.activities.MapActivity;
|
||||
import net.osmand.plus.dashboard.tools.DashFragmentData;
|
||||
import net.osmand.plus.firstusage.FirstUsageWizardFragment;
|
||||
import net.osmand.plus.server.ServerFragment;
|
||||
import net.osmand.plus.settings.fragments.BaseSettingsFragment;
|
||||
import net.osmand.plus.views.layers.MapInfoLayer;
|
||||
import net.osmand.plus.views.OsmandMapLayer.DrawSettings;
|
||||
|
@ -21,6 +26,7 @@ import net.osmand.plus.views.OsmandMapTileView;
|
|||
import net.osmand.plus.views.mapwidgets.widgets.TextInfoWidget;
|
||||
|
||||
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_BUILDS_ID;
|
||||
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_WEBSERVER_ID;
|
||||
|
||||
public class OsmandDevelopmentPlugin extends OsmandPlugin {
|
||||
|
||||
|
@ -71,10 +77,29 @@ public class OsmandDevelopmentPlugin extends OsmandPlugin {
|
|||
return true;
|
||||
}
|
||||
}).createItem());
|
||||
}
|
||||
|
||||
helper.addItem(new ContextMenuItem.ItemBuilder().setTitleId(R.string.web_server, mapActivity)
|
||||
.setId(DRAWER_WEBSERVER_ID)
|
||||
.setIcon(R.drawable.mm_shop_computer)
|
||||
.setListener(new ContextMenuAdapter.ItemClickListener() {
|
||||
@Override
|
||||
public boolean onContextMenuClick(ArrayAdapter<ContextMenuItem> adapter, int itemId, int pos, boolean isChecked, int[] viewCoordinates) {
|
||||
Fragment fragment = new ServerFragment();
|
||||
showFragment(mapActivity, fragment);
|
||||
return true;
|
||||
}
|
||||
}).createItem());
|
||||
}
|
||||
}
|
||||
|
||||
private static void showFragment(FragmentActivity activity, Fragment fragment) {
|
||||
if (activity != null) {
|
||||
activity.getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.fragmentContainer, fragment, ServerFragment.TAG)
|
||||
.commitAllowingStateLoss();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void updateLayers(OsmandMapTileView mapView, MapActivity activity) {
|
||||
if (isActive()) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package net.osmand.plus.render;
|
||||
|
||||
import android.util.Log;
|
||||
import net.osmand.core.android.MapRendererView;
|
||||
import net.osmand.core.android.TileSourceProxyProvider;
|
||||
import net.osmand.core.jni.MapLayerConfiguration;
|
||||
|
@ -156,12 +157,19 @@ public class MapVectorLayer extends BaseMapLayer {
|
|||
mapRenderer.setVisualZoomShift(zoomMagnifier - 1.0f);
|
||||
} else {
|
||||
if (!view.isZooming()) {
|
||||
if (resourceManager.updateRenderedMapNeeded(tilesRect, drawSettings)) {
|
||||
if (resourceManager.updateRenderedMapNeeded(tilesRect, drawSettings) ||
|
||||
view.isScreenViewDetached()) {
|
||||
// pixRect.set(-view.getWidth(), -view.getHeight() / 2, 2 * view.getWidth(), 3 *
|
||||
// view.getHeight() / 2);
|
||||
final RotatedTileBox copy = tilesRect.copy();
|
||||
copy.increasePixelDimensions(copy.getPixWidth() / 3, copy.getPixHeight() / 4);
|
||||
resourceManager.updateRendererMap(copy, null);
|
||||
Log.d("SERVER: ","SERVER: interrupt in layer");
|
||||
if (view.isScreenViewDetached()){
|
||||
resourceManager.getRenderer().loadMap(copy, resourceManager.getMapTileDownloader());
|
||||
}
|
||||
else {
|
||||
copy.increasePixelDimensions(copy.getPixWidth() / 3, copy.getPixHeight() / 4);
|
||||
resourceManager.updateRendererMap(copy, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -174,7 +182,7 @@ public class MapVectorLayer extends BaseMapLayer {
|
|||
|
||||
private boolean drawRenderedMap(Canvas canvas, Bitmap bmp, RotatedTileBox bmpLoc, RotatedTileBox currentViewport) {
|
||||
boolean shown = false;
|
||||
if (bmp != null && bmpLoc != null) {
|
||||
if (bmp != null && bmpLoc != null) {
|
||||
float rot = -bmpLoc.getRotate();
|
||||
canvas.rotate(rot, currentViewport.getCenterPixelX(), currentViewport.getCenterPixelY());
|
||||
final RotatedTileBox calc = currentViewport.copy();
|
||||
|
|
|
@ -69,6 +69,10 @@ public class AsyncLoadingThread extends Thread {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean areResourcesLoading() {
|
||||
return !requests.isEmpty();
|
||||
}
|
||||
|
||||
public void requestToLoadTile(TileLoadDownloadRequest req) {
|
||||
requests.push(req);
|
||||
}
|
||||
|
|
|
@ -1040,7 +1040,7 @@ public class ResourceManager {
|
|||
return renderer.updateMapIsNeeded(rotatedTileBox, drawSettings);
|
||||
}
|
||||
|
||||
public void updateRendererMap(RotatedTileBox rotatedTileBox, OnMapLoadedListener mapLoadedListener){
|
||||
public synchronized void updateRendererMap(RotatedTileBox rotatedTileBox, OnMapLoadedListener mapLoadedListener){
|
||||
renderer.interruptLoadingMap();
|
||||
asyncLoadingThread.requestToLoadMap(new MapLoadRequest(rotatedTileBox, mapLoadedListener));
|
||||
}
|
||||
|
@ -1177,6 +1177,11 @@ public class ResourceManager {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public AsyncLoadingThread getAsyncLoadingThread() {
|
||||
return asyncLoadingThread;
|
||||
}
|
||||
|
||||
/// On low memory method ///
|
||||
public void onLowMemory() {
|
||||
log.info("On low memory");
|
||||
|
|
164
OsmAnd/src/net/osmand/plus/server/OsmAndHttpServer.java
Normal file
164
OsmAnd/src/net/osmand/plus/server/OsmAndHttpServer.java
Normal file
|
@ -0,0 +1,164 @@
|
|||
package net.osmand.plus.server;
|
||||
|
||||
import android.webkit.MimeTypeMap;
|
||||
import fi.iki.elonen.NanoHTTPD;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.data.RotatedTileBox;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.activities.MapActivity;
|
||||
import net.osmand.plus.server.endpoints.TileEndpoint;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
public class OsmAndHttpServer extends NanoHTTPD {
|
||||
private static final String ASSETS_FOLDER_NAME = "server";
|
||||
private static final org.apache.commons.logging.Log LOG = PlatformUtil.getLog(OsmAndHttpServer.class);
|
||||
private final Map<String, ApiEndpoint> endpoints = new HashMap<>();
|
||||
private MapActivity mapActivity;
|
||||
private RotatedTileBox mapTileBoxCopy;
|
||||
private boolean mapLinkedToLocation;
|
||||
private OsmandApplication app;
|
||||
|
||||
public OsmAndHttpServer(String hostname, int port) {
|
||||
super(hostname, port);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Response serve(IHTTPSession session) {
|
||||
String uri = session.getUri();
|
||||
if (uri.equals("/")) {
|
||||
return getStatic("/index.html");
|
||||
}
|
||||
if (isApiUrl(uri)) {
|
||||
return routeApi(session);
|
||||
}
|
||||
return getStatic(uri);
|
||||
}
|
||||
|
||||
public void start(MapActivity mapActivity) throws IOException {
|
||||
this.mapActivity = mapActivity;
|
||||
// don't leak map activity with applciation
|
||||
this.app = mapActivity.getMyApplication();
|
||||
registerEndpoints();
|
||||
start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
|
||||
mapActivity.getMapView().setScreenViewDetached(true);
|
||||
this.mapTileBoxCopy = mapActivity.getMapView().getCurrentRotatedTileBox().copy();
|
||||
mapLinkedToLocation = mapActivity.getMapViewTrackingUtilities().isMapLinkedToLocation();
|
||||
mapActivity.getMapViewTrackingUtilities().setMapLinkedToLocation(false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
mapActivity.getMapView().setScreenViewDetached(false);
|
||||
mapActivity.getMapView().setCurrentViewport(mapTileBoxCopy);
|
||||
mapActivity.getMapViewTrackingUtilities().setMapLinkedToLocation(mapLinkedToLocation);
|
||||
mapActivity = null;
|
||||
super.stop();
|
||||
}
|
||||
|
||||
public MapActivity getMapActivity() {
|
||||
return mapActivity;
|
||||
}
|
||||
|
||||
public OsmandApplication getMyApplication() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
RotatedTileBox rtb = mapActivity.getMapView().getCurrentRotatedTileBox();
|
||||
float lat = (float) rtb.getLatitude();
|
||||
float lon = (float) rtb.getLongitude();
|
||||
int z = rtb.getZoom();
|
||||
return String.format("http://%s:%d/?lat=%.4f&lon%.4f&zoom=%d", getHostname(), getListeningPort(),
|
||||
lat, lon, z);
|
||||
}
|
||||
|
||||
private NanoHTTPD.Response routeApi(NanoHTTPD.IHTTPSession session) {
|
||||
String uri = session.getUri();
|
||||
Iterator<Map.Entry<String, ApiEndpoint>> it = endpoints.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, ApiEndpoint> e = it.next();
|
||||
if (uri.startsWith(e.getKey())) {
|
||||
try {
|
||||
return e.getValue().process(session, uri);
|
||||
} catch (Exception exception) {
|
||||
LOG.error("SERVER ERROR: " + exception.getMessage());
|
||||
return ErrorResponses.response500;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ErrorResponses.response404;
|
||||
}
|
||||
|
||||
private boolean isApiUrl(String uri) {
|
||||
for (String endpoint : endpoints.keySet()) {
|
||||
int stringLength = endpoint.length();
|
||||
if (uri.startsWith(endpoint) &&
|
||||
(uri.length() == endpoint.length() || uri.charAt(stringLength) == '/')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void registerEndpoints() {
|
||||
register("/tile", new TileEndpoint(this));
|
||||
}
|
||||
|
||||
private void register(String path, ApiEndpoint endpoint) {
|
||||
endpoints.put(path, endpoint);
|
||||
}
|
||||
|
||||
private NanoHTTPD.Response getStatic(String uri) {
|
||||
InputStream is;
|
||||
String mimeType = parseMimeType(uri);
|
||||
OsmandApplication app = mapActivity.getMyApplication();
|
||||
if (app != null) {
|
||||
try {
|
||||
is = app.getAssets().open(ASSETS_FOLDER_NAME + uri);
|
||||
if (is.available() == 0) {
|
||||
return ErrorResponses.response404;
|
||||
}
|
||||
return newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.OK,
|
||||
mimeType,
|
||||
is,
|
||||
is.available());
|
||||
} catch (IOException e) {
|
||||
LOG.error(e);
|
||||
return ErrorResponses.response404;
|
||||
}
|
||||
}
|
||||
return ErrorResponses.response500;
|
||||
}
|
||||
|
||||
private String parseMimeType(String url) {
|
||||
String type = "text/plain";
|
||||
if (url.endsWith(".js")) return "text/javascript";
|
||||
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
|
||||
if (extension != null) {
|
||||
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
public interface ApiEndpoint {
|
||||
NanoHTTPD.Response process(IHTTPSession session, String url);
|
||||
}
|
||||
|
||||
public static class ErrorResponses {
|
||||
public static NanoHTTPD.Response response404 =
|
||||
newFixedLengthResponse(NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
NanoHTTPD.MIME_PLAINTEXT, "404 Not Found");
|
||||
|
||||
public static NanoHTTPD.Response response500 =
|
||||
newFixedLengthResponse(NanoHTTPD.Response.Status.INTERNAL_ERROR,
|
||||
NanoHTTPD.MIME_PLAINTEXT, "500 Internal Server Error");
|
||||
}
|
||||
}
|
126
OsmAnd/src/net/osmand/plus/server/ServerFragment.java
Normal file
126
OsmAnd/src/net/osmand/plus/server/ServerFragment.java
Normal file
|
@ -0,0 +1,126 @@
|
|||
package net.osmand.plus.server;
|
||||
|
||||
import android.net.TrafficStats;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.StrictMode;
|
||||
import android.text.format.Formatter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import fi.iki.elonen.NanoHTTPD;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.activities.MapActivity;
|
||||
import net.osmand.plus.base.BaseOsmAndFragment;
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static android.content.Context.WIFI_SERVICE;
|
||||
|
||||
public class ServerFragment extends BaseOsmAndFragment {
|
||||
public static final String TAG = "ServerFrag";
|
||||
private final static Log LOG = PlatformUtil.getLog(ServerFragment.class);
|
||||
private final int port = 24990;
|
||||
final int THREAD_ID = 14231; // random number
|
||||
private boolean initialized = false;
|
||||
private OsmAndHttpServer server;
|
||||
private View view;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
enableStrictMode();
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
view = inflater.inflate(R.layout.server_fragment, container, false);
|
||||
view.findViewById(R.id.server_start_button).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (!initialized) {
|
||||
updateTextView(getString(R.string.stop_web_server));
|
||||
initServer();
|
||||
}
|
||||
}
|
||||
});
|
||||
view.findViewById(R.id.server_stop_button).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
updateTextView(getString(R.string.start_web_server));
|
||||
deInitServer();
|
||||
}
|
||||
});
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
deInitServer();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
public static void enableStrictMode() {
|
||||
StrictMode.setThreadPolicy(
|
||||
new StrictMode.ThreadPolicy.Builder()
|
||||
.detectDiskReads()
|
||||
.detectDiskWrites()
|
||||
.detectNetwork()
|
||||
.permitDiskReads()
|
||||
.permitDiskWrites()
|
||||
.penaltyLog()
|
||||
.build());
|
||||
StrictMode.setVmPolicy(
|
||||
new StrictMode.VmPolicy.Builder()
|
||||
.detectLeakedSqlLiteObjects()
|
||||
.penaltyLog()
|
||||
.build());
|
||||
}
|
||||
|
||||
private void updateTextView(String text) {
|
||||
((TextView) view.findViewById(R.id.server_status_textview)).setText(text);
|
||||
}
|
||||
|
||||
private void initServer() {
|
||||
TrafficStats.setThreadStatsTag(THREAD_ID);
|
||||
String hostname = getDeviceAddress();
|
||||
try {
|
||||
server = new OsmAndHttpServer(hostname, port);
|
||||
server.start((MapActivity) getActivity());
|
||||
initialized = true;
|
||||
updateTextView("Server started at " + server.getUrl());
|
||||
} catch (IOException e) {
|
||||
Toast.makeText(requireContext(),
|
||||
e.getLocalizedMessage(),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getDeviceAddress() {
|
||||
WifiManager wm = (WifiManager) requireContext().getSystemService(WIFI_SERVICE);
|
||||
String ip = Formatter.formatIpAddress(wm.getConnectionInfo().getIpAddress());
|
||||
return ip != null ? ip : "0.0.0.0";
|
||||
}
|
||||
|
||||
private void deInitServer() {
|
||||
if (server != null) {
|
||||
server.closeAllConnections();
|
||||
server.stop();
|
||||
}
|
||||
initialized = false;
|
||||
if (getActivity() != null) {
|
||||
try {
|
||||
getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();
|
||||
} catch (RuntimeException e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
package net.osmand.plus.server.endpoints;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.data.RotatedTileBox;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.util.MapUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
public class MetaTileFileSystemCache {
|
||||
private static final Log LOG = PlatformUtil.getLog(TileEndpoint.class);
|
||||
private static final String TILES_FOLDER = "webtiles";
|
||||
static final int TILE_SIZE_PX = 256;
|
||||
static final int TILE_DENSITY = 2;
|
||||
static final int METATILE_SIZE = 2;
|
||||
private static final int MAX_IN_MEMORY_CACHE_SIZE = 16 / METATILE_SIZE;
|
||||
private static final int MAX_CACHE_SIZE = 128;
|
||||
|
||||
private final ConcurrentLinkedQueue<MetaTileCache> inMemoryCache = new ConcurrentLinkedQueue<>();
|
||||
private final File externalCacheDir;
|
||||
|
||||
public MetaTileFileSystemCache(OsmandApplication application) {
|
||||
externalCacheDir = application.getAppPath(TILES_FOLDER);
|
||||
if (!externalCacheDir.exists()) {
|
||||
externalCacheDir.mkdir();
|
||||
}
|
||||
}
|
||||
|
||||
public void put(MetaTileCache tile) {
|
||||
// TODO list files too slow, better to have local variable to monitor or local list
|
||||
while (externalCacheDir.listFiles().length > MAX_CACHE_SIZE) {
|
||||
for (int i = 0; i < externalCacheDir.listFiles().length - MAX_CACHE_SIZE; i++) {
|
||||
externalCacheDir.listFiles()[i].delete();
|
||||
}
|
||||
}
|
||||
String fileName = tile.getTileId();
|
||||
File file = new File(externalCacheDir, fileName);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
try {
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
tile.bmp.compress(Bitmap.CompressFormat.PNG, 100, out);
|
||||
out.flush();
|
||||
out.close();
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
}
|
||||
if (reserveMemSlot()) {
|
||||
inMemoryCache.add(tile);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean reserveMemSlot() {
|
||||
while (MAX_IN_MEMORY_CACHE_SIZE > 0 && inMemoryCache.size() >= MAX_IN_MEMORY_CACHE_SIZE) {
|
||||
inMemoryCache.poll();
|
||||
}
|
||||
return MAX_IN_MEMORY_CACHE_SIZE > 0;
|
||||
}
|
||||
|
||||
public MetaTileCache get(int zoom, int x, int y) {
|
||||
int mx = (x / METATILE_SIZE) * METATILE_SIZE;
|
||||
int my = (y / METATILE_SIZE) * METATILE_SIZE;
|
||||
for (MetaTileCache r : inMemoryCache) {
|
||||
if (r.zoom == zoom && r.ex >= x && r.ey >= y && r.sx <= x && r.sy <= y) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
File file = new File(externalCacheDir, zoom + "_" + METATILE_SIZE + "_" + mx + "_" + my);
|
||||
if (file.exists()) {
|
||||
MetaTileCache tile = new MetaTileCache(
|
||||
BitmapFactory.decodeFile(file.getAbsolutePath()),
|
||||
mx, my, mx + METATILE_SIZE - 1, my + METATILE_SIZE - 1, zoom);
|
||||
if (reserveMemSlot()) {
|
||||
inMemoryCache.add(tile);
|
||||
}
|
||||
return tile;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void clearCache() {
|
||||
clearInMemoryCache();
|
||||
clearFileCache();
|
||||
}
|
||||
|
||||
private void clearFileCache() {
|
||||
for (int i = 0; i < externalCacheDir.listFiles().length; i++) {
|
||||
externalCacheDir.listFiles()[i].delete();
|
||||
}
|
||||
}
|
||||
|
||||
private void clearInMemoryCache() {
|
||||
inMemoryCache.clear();
|
||||
}
|
||||
|
||||
public MetaTileCache createMetaTile(int zoom, int x, int y) {
|
||||
int mx = (x / METATILE_SIZE) * METATILE_SIZE;
|
||||
int my = (y / METATILE_SIZE) * METATILE_SIZE;
|
||||
double lat = MapUtils.getLatitudeFromTile(zoom, my + 0.5 * METATILE_SIZE);
|
||||
double lon = MapUtils.getLongitudeFromTile(zoom, mx + 0.5 * METATILE_SIZE);
|
||||
MetaTileCache res = new MetaTileCache();
|
||||
res.bbox = new RotatedTileBox.RotatedTileBoxBuilder()
|
||||
.setLocation(lat, lon)
|
||||
.setMapDensity(TILE_DENSITY).density(TILE_DENSITY)
|
||||
.setZoom(zoom)
|
||||
.setPixelDimensions(TILE_SIZE_PX * TILE_DENSITY * METATILE_SIZE,
|
||||
TILE_SIZE_PX * TILE_DENSITY * METATILE_SIZE, 0.5f, 0.5f).build();
|
||||
res.sx = mx;
|
||||
res.ex = mx + METATILE_SIZE - 1;
|
||||
res.sy = my;
|
||||
res.ey = my + METATILE_SIZE - 1;
|
||||
res.zoom = zoom;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
public static class MetaTileCache {
|
||||
Bitmap bmp;
|
||||
int sx;
|
||||
int sy;
|
||||
int ex;
|
||||
int ey;
|
||||
int zoom;
|
||||
public RotatedTileBox bbox;
|
||||
|
||||
public MetaTileCache() {
|
||||
|
||||
}
|
||||
|
||||
public MetaTileCache(Bitmap bmp, int sx, int sy, int ex, int ey, int zoom) {
|
||||
this.bmp = bmp;
|
||||
this.sx = sx;
|
||||
this.sy = sy;
|
||||
this.ex = ex;
|
||||
this.ey = ey;
|
||||
this.zoom = zoom;
|
||||
}
|
||||
|
||||
// to be used in file name
|
||||
public String getTileId() {
|
||||
return zoom + "_" + METATILE_SIZE + "_" + sx + "_" + sy;
|
||||
}
|
||||
|
||||
public Bitmap getBitmap() {
|
||||
return bmp;
|
||||
}
|
||||
|
||||
public Bitmap getSubtile(int x, int y) {
|
||||
return Bitmap.createBitmap(bmp,
|
||||
(x - sx) * TILE_SIZE_PX * TILE_DENSITY,
|
||||
(y - sy) * TILE_SIZE_PX * TILE_DENSITY,
|
||||
TILE_SIZE_PX * TILE_DENSITY, TILE_SIZE_PX * TILE_DENSITY);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
120
OsmAnd/src/net/osmand/plus/server/endpoints/TileEndpoint.java
Normal file
120
OsmAnd/src/net/osmand/plus/server/endpoints/TileEndpoint.java
Normal file
|
@ -0,0 +1,120 @@
|
|||
package net.osmand.plus.server.endpoints;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import fi.iki.elonen.NanoHTTPD;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.data.RotatedTileBox;
|
||||
import net.osmand.plus.activities.MapActivity;
|
||||
import net.osmand.plus.resources.ResourceManager;
|
||||
import net.osmand.plus.server.OsmAndHttpServer;
|
||||
import net.osmand.plus.views.OsmandMapLayer;
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
import static fi.iki.elonen.NanoHTTPD.newFixedLengthResponse;
|
||||
|
||||
public class TileEndpoint implements OsmAndHttpServer.ApiEndpoint {
|
||||
private static final int TIMEOUT_STEP = 150;
|
||||
private static final int TIMEOUT = 15000;
|
||||
private static final Log LOG = PlatformUtil.getLog(TileEndpoint.class);
|
||||
|
||||
private final RotatedTileBox mapTileBoxCopy;
|
||||
private final OsmAndHttpServer server;
|
||||
private final MetaTileFileSystemCache cache;
|
||||
private int lastRequestedZoom;
|
||||
|
||||
public TileEndpoint(OsmAndHttpServer server) {
|
||||
this.server = server;
|
||||
this.cache = new MetaTileFileSystemCache(server.getMyApplication());
|
||||
this.mapTileBoxCopy = server.getMapActivity().getMapView().getCurrentRotatedTileBox().copy();
|
||||
this.cache.clearCache();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NanoHTTPD.Response process(NanoHTTPD.IHTTPSession session, String url) {
|
||||
// https://tile.osmand.net/hd/6/55/25.png
|
||||
int extInd = url.indexOf('.');
|
||||
if (extInd >= 0) {
|
||||
url = url.substring(0, extInd);
|
||||
}
|
||||
if (url.charAt(0) == '/') {
|
||||
url = url.substring(1);
|
||||
}
|
||||
String[] prms = url.split("/");
|
||||
if (prms.length < 4) {
|
||||
return OsmAndHttpServer.ErrorResponses.response500;
|
||||
}
|
||||
int zoom = Integer.parseInt(prms[1]);
|
||||
int x = Integer.parseInt(prms[2]);
|
||||
int y = Integer.parseInt(prms[3]);
|
||||
MetaTileFileSystemCache.MetaTileCache res = cache.get(zoom, x, y);
|
||||
if (res == null) {
|
||||
synchronized (this) {
|
||||
lastRequestedZoom = zoom;
|
||||
}
|
||||
res = requestMetatile(x, y, zoom);
|
||||
if (res == null) {
|
||||
return OsmAndHttpServer.ErrorResponses.response500;
|
||||
}
|
||||
}
|
||||
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
Bitmap bmp = res.getSubtile(x, y);
|
||||
if (bmp == null) {
|
||||
LOG.error("SERVER: Cannot cut bitmap");
|
||||
return OsmAndHttpServer.ErrorResponses.response500;
|
||||
}
|
||||
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
||||
byte[] byteArray = stream.toByteArray();
|
||||
ByteArrayInputStream str = new ByteArrayInputStream(byteArray);
|
||||
return newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.OK, "image/png",
|
||||
str, str.available());
|
||||
}
|
||||
|
||||
|
||||
private synchronized MetaTileFileSystemCache.MetaTileCache requestMetatile(int x, int y, int zoom) {
|
||||
long tm = System.currentTimeMillis();
|
||||
MapActivity mapActivity = server.getMapActivity();
|
||||
ResourceManager resourceManager = mapActivity.getMyApplication().getResourceManager();
|
||||
if (mapActivity == null) {
|
||||
return null;
|
||||
}
|
||||
MetaTileFileSystemCache.MetaTileCache cacheTile = this.cache.get(zoom, x, y);
|
||||
if (cacheTile != null) {
|
||||
return cacheTile;
|
||||
}
|
||||
MetaTileFileSystemCache.MetaTileCache res = cache.createMetaTile(zoom, x, y);
|
||||
mapActivity.getMapView().setCurrentViewport(res.bbox);
|
||||
int timeout = 0;
|
||||
try {
|
||||
LOG.debug("SERVER: interrupt in request");
|
||||
resourceManager.getRenderer().loadMap(res.bbox, resourceManager.getMapTileDownloader());
|
||||
Thread.sleep(TIMEOUT_STEP); // to do line should be removed in future
|
||||
OsmandMapLayer.DrawSettings drawSettings =
|
||||
new OsmandMapLayer.DrawSettings(mapActivity.getMapView().getSettings().isLightContent(),
|
||||
true);
|
||||
mapActivity.getMapView().refreshMapInternal(drawSettings);
|
||||
mapActivity.getMapView().refreshBaseMapInternal(res.bbox, drawSettings);
|
||||
Thread.sleep(TIMEOUT_STEP); // to do line should be removed in future
|
||||
// wait for image to be refreshed
|
||||
while (!resourceManager.getRenderingBufferImageThread().getLooper().getQueue().isIdle() &&
|
||||
timeout < TIMEOUT) {
|
||||
Thread.sleep(TIMEOUT_STEP);
|
||||
timeout += TIMEOUT_STEP;
|
||||
}
|
||||
Bitmap rbmp = mapActivity.getMapView().getBufferBitmap();
|
||||
res.bmp = rbmp.copy(rbmp.getConfig(), true);
|
||||
this.cache.put(res);
|
||||
LOG.debug("SERVER: metatile: " + (System.currentTimeMillis() - tm) / 1000.0f);
|
||||
return res;
|
||||
} catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
LOG.debug("SERVER: metatile1: " + (System.currentTimeMillis() - tm) / 1000.0f);
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -77,6 +77,7 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
protected OsmandSettings settings = null;
|
||||
private CanvasColors canvasColors = null;
|
||||
private Boolean nightMode = null;
|
||||
private boolean isScreenViewDetached = false;
|
||||
|
||||
private class CanvasColors {
|
||||
int colorDay = MAP_DEFAULT_COLOR;
|
||||
|
@ -283,6 +284,14 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
return layers.contains(layer);
|
||||
}
|
||||
|
||||
public boolean isScreenViewDetached() {
|
||||
return isScreenViewDetached;
|
||||
}
|
||||
|
||||
public void setScreenViewDetached(boolean screenViewDetached) {
|
||||
isScreenViewDetached = screenViewDetached;
|
||||
}
|
||||
|
||||
public float getZorder(OsmandMapLayer layer) {
|
||||
Float z = zOrders.get(layer);
|
||||
if (z == null) {
|
||||
|
@ -579,7 +588,7 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
}
|
||||
}
|
||||
|
||||
private void refreshBaseMapInternal(RotatedTileBox tileBox, DrawSettings drawSettings) {
|
||||
public void refreshBaseMapInternal(RotatedTileBox tileBox, DrawSettings drawSettings) {
|
||||
if (tileBox.getPixHeight() == 0 || tileBox.getPixWidth() == 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -616,7 +625,7 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
additional.calculateFPS(start, end);
|
||||
}
|
||||
|
||||
private void refreshMapInternal(DrawSettings drawSettings) {
|
||||
public void refreshMapInternal(DrawSettings drawSettings) {
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -643,9 +652,9 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
}
|
||||
final int cy = (int) (ratioy * view.getHeight());
|
||||
final int cx = (int) (ratiox * view.getWidth());
|
||||
if (currentViewport.getPixWidth() != view.getWidth() || currentViewport.getPixHeight() != view.getHeight() ||
|
||||
if ((currentViewport.getPixWidth() != view.getWidth() || currentViewport.getPixHeight() != view.getHeight() ||
|
||||
currentViewport.getCenterPixelY() != cy ||
|
||||
currentViewport.getCenterPixelX() != cx) {
|
||||
currentViewport.getCenterPixelX() != cx) && !isScreenViewDetached) {
|
||||
currentViewport.setPixelDimensions(view.getWidth(), view.getHeight(), ratiox, ratioy);
|
||||
refreshBufferImage(drawSettings);
|
||||
}
|
||||
|
@ -779,7 +788,7 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
canvas.drawCircle(x, y, 7 * dm.density, paintCenter);
|
||||
}
|
||||
|
||||
private void refreshBufferImage(final DrawSettings drawSettings) {
|
||||
public void refreshBufferImage(final DrawSettings drawSettings) {
|
||||
if (mapRenderer != null) {
|
||||
return;
|
||||
}
|
||||
|
@ -821,17 +830,17 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
|
||||
// this method could be called in non UI thread
|
||||
public void refreshMap(final boolean updateVectorRendering) {
|
||||
if (view != null && view.isShown()) {
|
||||
boolean nightMode = application.getDaynightHelper().isNightMode();
|
||||
Boolean currentNightMode = this.nightMode;
|
||||
boolean forceUpdateVectorDrawing = currentNightMode != null && currentNightMode != nightMode;
|
||||
if (forceUpdateVectorDrawing) {
|
||||
resetDefaultColor();
|
||||
}
|
||||
this.nightMode = nightMode;
|
||||
DrawSettings drawSettings = new DrawSettings(nightMode, updateVectorRendering || forceUpdateVectorDrawing);
|
||||
sendRefreshMapMsg(drawSettings, 20);
|
||||
refreshBufferImage(drawSettings);
|
||||
if ((view != null && view.isShown()) || isScreenViewDetached) {
|
||||
// boolean nightMode = application.getDaynightHelper().isNightMode();
|
||||
// Boolean currentNightMode = this.nightMode;
|
||||
// boolean forceUpdateVectorDrawing = currentNightMode != null && currentNightMode != nightMode;
|
||||
// if (forceUpdateVectorDrawing) {
|
||||
// resetDefaultColor();
|
||||
// }
|
||||
// this.nightMode = nightMode;
|
||||
// DrawSettings drawSettings = new DrawSettings(nightMode, updateVectorRendering || forceUpdateVectorDrawing);
|
||||
// sendRefreshMapMsg(drawSettings, 20);
|
||||
// refreshBufferImage(drawSettings);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -869,6 +878,19 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
return currentViewport;
|
||||
}
|
||||
|
||||
public void setCurrentViewport(RotatedTileBox viewport) {
|
||||
currentViewport = viewport;
|
||||
//refreshMap(true);
|
||||
}
|
||||
|
||||
public Bitmap getBufferBitmap() {
|
||||
return bufferBitmap;
|
||||
}
|
||||
|
||||
public RotatedTileBox getBufferImgLoc() {
|
||||
return bufferImgLoc;
|
||||
}
|
||||
|
||||
public float getDensity() {
|
||||
return currentViewport.getDensity();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue