Add time expiration

This commit is contained in:
Victor Shcherb 2013-08-10 17:35:20 +02:00
parent dc126200c3
commit eb4480f8e1
11 changed files with 359 additions and 10 deletions

View file

@ -21,4 +21,6 @@ public interface ITileSource {
public boolean couldBeDownloadedFromInternet();
public int getExpirationTimeMillis();
}

View file

@ -32,7 +32,7 @@ public class TileSourceManager {
public static final String RULE_YANDEX_TRAFFIC = "yandex_traffic";
private static final String RULE_WMS = "wms_tile";
public static class TileSourceTemplate implements ITileSource {
public static class TileSourceTemplate implements ITileSource, Cloneable {
private int maxZoom;
private int minZoom;
private String name;
@ -41,8 +41,11 @@ public class TileSourceManager {
protected String ext;
private int avgSize;
private int bitDensity;
// -1 never expires,
private int expirationTimeMillis = -1;
private boolean ellipticYTile;
private String rule;
private boolean isRuleAcceptable = true;
public TileSourceTemplate(String name, String urlToLoad, String ext, int maxZoom, int minZoom, int tileSize, int bitDensity,
@ -57,6 +60,19 @@ public class TileSourceManager {
this.bitDensity = bitDensity;
}
public void setMinZoom(int minZoom) {
this.minZoom = minZoom;
}
public void setMaxZoom(int maxZoom) {
this.maxZoom = maxZoom;
}
public void setName(String name) {
this.name = name;
}
public void setEllipticYTile(boolean ellipticYTile) {
this.ellipticYTile = ellipticYTile;
}
@ -90,6 +106,27 @@ public class TileSourceManager {
return name;
}
public void setExpirationTimeMillis(int timeMillis) {
this.expirationTimeMillis = timeMillis;
}
public void setExpirationTimeMinutes(int minutes) {
if(minutes < 0) {
this.expirationTimeMillis = -1;
} else {
this.expirationTimeMillis = minutes * 60 * 1000;
}
}
public int getExpirationTimeMinutes() {
return expirationTimeMillis;
}
public int getExpirationTimeMillis() {
return expirationTimeMillis;
}
@Override
public int getTileSize() {
return tileSize;
@ -100,6 +137,14 @@ public class TileSourceManager {
return ext;
}
public void setTileFormat(String ext) {
this.ext = ext;
}
public void setUrlToLoad(String urlToLoad) {
this.urlToLoad = urlToLoad;
}
public boolean isRuleAcceptable() {
return isRuleAcceptable;
}
@ -108,6 +153,14 @@ public class TileSourceManager {
this.isRuleAcceptable = isRuleAcceptable;
}
public TileSourceTemplate copy() {
try {
return (TileSourceTemplate) this.clone();
} catch (CloneNotSupportedException e) {
return this;
}
}
@Override
public String getUrlToLoad(int x, int y, int zoom) {
// use int to string not format numbers! (non-nls)
@ -220,6 +273,9 @@ public class TileSourceManager {
if (tm.isEllipticYTile()) {
properties.put("ellipsoid", tm.isEllipticYTile() + "");
}
if (tm.getExpirationTimeMinutes() != -1) {
properties.put("expirationTimeMinutes", tm.getExpirationTimeMinutes() + "");
}
if (override || !metainfo.exists()) {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(metainfo)));
for (String key : properties.keySet()) {
@ -402,6 +458,7 @@ public class TileSourceManager {
int maxZoom = parseInt(attributes, "max_zoom", 18);
int minZoom = parseInt(attributes, "min_zoom", 5);
int tileSize = parseInt(attributes, "tile_size", 256);
int expirationTime = parseInt(attributes, "expirationTimeMinutes", -1);
String ext = attributes.get("ext") == null ? ".jpg" : attributes.get("ext");
int bitDensity = parseInt(attributes, "img_density", 16);
int avgTileSize = parseInt(attributes, "avg_img_size", 18000);
@ -410,6 +467,9 @@ public class TileSourceManager {
ellipsoid = true;
}
TileSourceTemplate templ = new TileSourceTemplate(name, urlTemplate, ext, maxZoom, minZoom, tileSize, bitDensity, avgTileSize);
if(expirationTime > 0) {
templ.setExpirationTimeMinutes(expirationTime);
}
templ.setEllipticYTile(ellipsoid);
return templ;
}
@ -426,6 +486,7 @@ public class TileSourceManager {
String ext = attributes.get("ext") == null ? ".jpg" : attributes.get("ext");
int bitDensity = parseInt(attributes, "img_density", 16);
int avgTileSize = parseInt(attributes, "avg_img_size", 18000);
int expirationTime = parseInt(attributes, "expirationTimeMinutes", -1);
boolean ellipsoid = false;
if (Boolean.parseBoolean(attributes.get("ellipsoid"))) {
ellipsoid = true;
@ -433,6 +494,9 @@ public class TileSourceManager {
TileSourceTemplate templ;
templ = new BeanShellTileSourceTemplate(name, urlTemplate, ext, maxZoom, minZoom, tileSize, bitDensity, avgTileSize);
templ.setEllipticYTile(ellipsoid);
if(expirationTime > 0) {
templ.setExpirationTimeMinutes(expirationTime);
}
return templ;
}

View file

@ -0,0 +1,139 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:orientation="vertical" >
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:stretchColumns="1" >
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/edit_tilesource_name" />
<EditText
android:id="@+id/Name"
android:layout_width="250dp"
android:minWidth="250dp"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:text="" >
<requestFocus />
</EditText>
</TableRow>
<TableRow android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/edit_tilesource_choose_existing" >
</TextView>
<Spinner
android:id="@+id/TileSourceSpinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp" >
</Spinner>
</TableRow>
<TableRow android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/edit_tilesource_url_to_load" />
<EditText
android:id="@+id/URLToLoad"
android:layout_width="250dp"
android:minWidth="250dp"
android:layout_height="wrap_content"
android:lines="5"
android:minLines="2"
android:text="" >
</EditText>
</TableRow>
<TableRow android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/edit_tilesource_minzoom" />
<EditText
android:id="@+id/MinZoom"
android:layout_width="250dp"
android:minWidth="250dp"
android:layout_height="wrap_content"
android:text="" >
</EditText>
</TableRow>
<TableRow android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/edit_tilesource_maxzoom" />
<EditText
android:id="@+id/MaxZoom"
android:layout_width="250dp"
android:minWidth="250dp"
android:layout_height="wrap_content"
android:text="" >
</EditText>
</TableRow>
<TableRow android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/edit_tilesource_expiration_time"
/>
<EditText
android:id="@+id/ExpirationTime"
android:layout_width="250dp"
android:minWidth="250dp"
android:layout_height="wrap_content"
android:text="" >
</EditText>
</TableRow>
<TableRow android:layout_width="fill_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="@+id/EllipticMercator"
android:layout_width="wrap_content"
android:layout_marginRight="5dp"
android:layout_span="2"
android:text="@string/edit_tilesource_elliptic_tile" />
</TableRow>
</TableLayout>
</LinearLayout>
</ScrollView>

View file

@ -9,6 +9,15 @@
3. All your modified/created strings are in the top of the file (to make easier find what\'s translated).
PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy
-->
<string name="edit_tilesource_successfully">Tilesource %1$s is successfully saved</string>
<string name="edit_tilesource_elliptic_tile">Elliptic mercator</string>
<string name="edit_tilesource_maxzoom">Max zoom</string>
<string name="edit_tilesource_expiration_time">Expire (minutes)</string>
<string name="edit_tilesource_minzoom">Min zoom</string>
<string name="edit_tilesource_url_to_load">URL</string>
<string name="edit_tilesource_choose_existing">Choose existing...</string>
<string name="edit_tilesource_name">Name</string>
<string name="maps_define_edit">Define/Edit&#8230;</string>
<string name="map_widget_fps_info">FPS debug info</string>
<string name="driving_region_descr">Select Driving Region : US, Europe, UK, Asia and Others</string>
<string name="driving_region">Driving Region</string>

View file

@ -920,6 +920,11 @@ public class OsmandSettings {
}
public Map<String, String> getTileSourceEntries(){
return getTileSourceEntries(true);
}
public Map<String, String> getTileSourceEntries(boolean sqlite){
Map<String, String> map = new LinkedHashMap<String, String>();
File dir = ctx.getAppPath(IndexConstants.TILES_INDEX_DIR);
if (dir != null && dir.canRead()) {
@ -936,11 +941,13 @@ public class OsmandSettings {
}
});
if (files != null) {
if (files != null ) {
for (File f : files) {
if (f.getName().endsWith(IndexConstants.SQLITE_EXT)) {
if(sqlite) {
String n = f.getName();
map.put(f.getName(), n.substring(0, n.lastIndexOf('.')));
}
} else if (f.isDirectory() && !f.getName().equals(IndexConstants.TEMP_SOURCE_TO_LOAD)
&& !f.getName().startsWith(".")) {
map.put(f.getName(), f.getName());

View file

@ -409,6 +409,11 @@ public class SQLiteTileSource implements ITileSource {
return false;
}
@Override
public int getExpirationTimeMillis() {
return -1;
}
}

View file

@ -149,10 +149,6 @@ public class MainMenuActivity extends Activity {
public void onClick(View widget) {
final Intent mapIntent = new Intent(activity, ContributionVersionActivity.class);
activity.startActivityForResult(mapIntent, 0);
// test geo activity
// String uri = "geo:0,0?q=Amsterdamseweg";
// Intent intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(uri));
// activity.startActivity(intent);
}
}, 0, content.length(), 0);
textVersionView.setText(content);

View file

@ -628,10 +628,12 @@ public class MapActivityLayers {
final String layerOsmVector = "LAYER_OSM_VECTOR";
final String layerInstallMore = "LAYER_INSTALL_MORE";
final String layerEditInstall = "LAYER_EDIT";
entriesMap.put(layerOsmVector, getString(R.string.vector_data));
entriesMap.putAll(settings.getTileSourceEntries());
entriesMap.put(layerInstallMore, getString(R.string.install_more));
entriesMap.put(layerEditInstall, getString(R.string.maps_define_edit));
final List<Entry<String, String>> entriesMapList = new ArrayList<Entry<String, String>>(entriesMap.entrySet());
@ -671,6 +673,23 @@ public class MapActivityLayers {
if (layerKey.equals(layerOsmVector)) {
settings.MAP_ONLINE_DATA.set(false);
updateMapSource(mapView, null);
} else if (layerKey.equals(layerEditInstall)) {
OsmandRasterMapsPlugin.defineNewEditLayer(activity, new ResultMatcher<TileSourceTemplate>() {
@Override
public boolean publish(TileSourceTemplate object) {
settings.MAP_TILE_SOURCES.set(object.getName());
settings.MAP_ONLINE_DATA.set(true);
updateMapSource(mapView, settings.MAP_TILE_SOURCES);
return true;
}
@Override
public boolean isCancelled() {
return false;
}
});
} else if (layerKey.equals(layerInstallMore)) {
OsmandRasterMapsPlugin.installMapLayers(activity, new ResultMatcher<TileSourceTemplate>() {
TileSourceTemplate template = null;

View file

@ -1,9 +1,11 @@
package net.osmand.plus.rastermaps;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.osmand.IndexConstants;
import net.osmand.ResultMatcher;
import net.osmand.StateChangedListener;
import net.osmand.access.AccessibleToast;
@ -34,6 +36,14 @@ import android.os.AsyncTask;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceScreen;
import android.support.v4.app.DialogFragment;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
public class OsmandRasterMapsPlugin extends OsmandPlugin {
@ -319,4 +329,93 @@ public class OsmandRasterMapsPlugin extends OsmandPlugin {
};
t.execute(new Void[0]);
}
public static void defineNewEditLayer(final MapActivity activity, final ResultMatcher<TileSourceTemplate> resultMatcher) {
final OsmandApplication app = (OsmandApplication) activity.getApplication();
final OsmandSettings settings = app.getSettings();
final Map<String, String> entriesMap = settings.getTileSourceEntries(false);
TileSourceTemplate ts = new TileSourceTemplate("NewMapnik","http://mapnik.osmand.net/{0}/{1}/{2}.png",
"png", 17, 5, 256, 16, 32000);
final TileSourceTemplate[] result = new TileSourceTemplate[] { ts };
Builder bld = new AlertDialog.Builder(activity);
View view = activity.getLayoutInflater().inflate(R.layout.editing_tile_source, null);
final EditText name = (EditText) view.findViewById(R.id.Name);
final Spinner existing = (Spinner) view.findViewById(R.id.TileSourceSpinner);
final EditText urlToLoad = (EditText) view.findViewById(R.id.URLToLoad);
final EditText minZoom = (EditText) view.findViewById(R.id.MinZoom);
final EditText maxZoom = (EditText) view.findViewById(R.id.MaxZoom);
final EditText expire = (EditText) view.findViewById(R.id.ExpirationTime);
final CheckBox elliptic = (CheckBox) view.findViewById(R.id.EllipticMercator);
updateTileSourceEditView(ts, name, urlToLoad, minZoom, maxZoom, expire, elliptic);
final ArrayList<String> templates = new ArrayList<String>(entriesMap.keySet());
templates.add(0, "");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(view.getContext(),
android.R.layout.simple_spinner_item,
templates
);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
existing.setAdapter(adapter);
existing.setSelection(0);
existing.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (position > 0) {
File f = activity.getMyApplication().getAppPath(IndexConstants.TILES_INDEX_DIR + templates.get(position));
TileSourceTemplate template = TileSourceManager.createTileSourceTemplate(f);
if (template != null) {
result[0] = template.copy();
updateTileSourceEditView(result[0], name, urlToLoad, minZoom, maxZoom, expire, elliptic);
}
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
bld.setView(view);
bld.setPositiveButton(R.string.default_buttons_save, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
TileSourceTemplate r = result[0];
try {
r.setName(name.getText().toString());
r.setExpirationTimeMinutes(expire.getText().length() == 0 ? - 1 :
Integer.parseInt(expire.getText().toString()));
r.setMinZoom(Integer.parseInt(minZoom.getText().toString()));
r.setMaxZoom(Integer.parseInt(maxZoom.getText().toString()));
r.setEllipticYTile(elliptic.isChecked());
r.setUrlToLoad(urlToLoad.getText().toString().isEmpty() ? null : urlToLoad.getText().toString().replace("{$x}", "{1}")
.replace("{$y}", "{2}").replace("{$z}", "{0}"));
if (r != null && r.getName().length() > 0) {
if (settings.installTileSource(r)) {
AccessibleToast.makeText(activity, activity.getString(R.string.edit_tilesource_successfully, r.getName()),
Toast.LENGTH_SHORT).show();
resultMatcher.publish(r);
}
}
} catch (RuntimeException e) {
AccessibleToast.makeText(activity, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
});
bld.setNegativeButton(R.string.default_buttons_cancel, null);
bld.show();
}
private static void updateTileSourceEditView(TileSourceTemplate ts, EditText name, final EditText urlToLoad, final EditText minZoom,
final EditText maxZoom, EditText expire, final CheckBox elliptic) {
minZoom.setText(ts.getMinimumZoomSupported()+"");
maxZoom.setText(ts.getMaximumZoomSupported()+"");
name.setText(ts.getName());
expire.setText(ts.getExpirationTimeMinutes() < 0 ? "" : ts.getExpirationTimeMinutes() + "");
urlToLoad.setText(ts.getUrlTemplate() == null? "" :
ts.getUrlTemplate().replace("{$x}", "{1}").replace("{$y}", "{2}").replace("{$z}", "{0}"));
elliptic.setChecked(ts.isEllipticYTile());
}
}

View file

@ -356,6 +356,10 @@ public class ResourceManager {
if (req.tileSource instanceof SQLiteTileSource) {
try {
bmp = ((SQLiteTileSource) req.tileSource).getImage(req.xTile, req.yTile, req.zoom);
// int ts = req.tileSource.getExpirationTimeMillis();
// if(ts != -1 && req.url != null && time - en.lastModified() > ts) {
// asyncLoadingThread.requestToDownload(req);
// }
} catch (OutOfMemoryError e) {
log.error("Out of memory error", e); //$NON-NLS-1$
clearTiles();
@ -365,6 +369,10 @@ public class ResourceManager {
if (en.exists()) {
try {
bmp = BitmapFactory.decodeFile(en.getAbsolutePath());
int ts = req.tileSource.getExpirationTimeMillis();
if(ts != -1 && req.url != null && time - en.lastModified() > ts) {
asyncLoadingThread.requestToDownload(req);
}
} catch (OutOfMemoryError e) {
log.error("Out of memory error", e); //$NON-NLS-1$
clearTiles();

View file

@ -83,6 +83,7 @@ public class YandexTrafficAdapter extends MapTileAdapter {
TileSourceTemplate template = new TileSourceTemplate(YANDEX_PREFFIX + mTimestamp,
"http://jgo.maps.yandex.net/1.1/tiles?l=trf,trfe&x={1}&y={2}&z={0}&tm=" + mTimestamp, ".png", 17, 7, 256, 8, 18000);
template.setEllipticYTile(true);
template.setExpirationTimeMinutes(20);
clearCache();
this.layer.setMapForMapTileAdapter(template, this);
}