From b180b6bd706932dccae3f552da03ec582a9b7ec8 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sun, 5 Dec 2010 13:12:50 +0000 Subject: [PATCH] implement batch tile downloader for android client git-svn-id: https://osmand.googlecode.com/svn/trunk@762 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8 --- OsmAnd/AndroidManifest.xml | 2 +- OsmAnd/res/layout-land/menu.xml | 2 +- OsmAnd/res/layout/download_tiles.xml | 25 ++ OsmAnd/res/layout/menu.xml | 2 +- OsmAnd/res/values-ru/strings.xml | 4 + OsmAnd/res/values/strings.xml | 5 + OsmAnd/src/net/osmand/ResourceManager.java | 4 + .../TransportIndexRepositoryBinary.java | 2 +- .../activities/DownloadIndexActivity.java | 3 + .../activities/DownloadTilesDialog.java | 235 ++++++++++++++++++ .../osmand/activities/MainMenuActivity.java | 16 +- .../net/osmand/activities/MapActivity.java | 5 + 12 files changed, 294 insertions(+), 11 deletions(-) create mode 100644 OsmAnd/res/layout/download_tiles.xml create mode 100644 OsmAnd/src/net/osmand/activities/DownloadTilesDialog.java diff --git a/OsmAnd/AndroidManifest.xml b/OsmAnd/AndroidManifest.xml index 758899a026..3fc4866d29 100644 --- a/OsmAnd/AndroidManifest.xml +++ b/OsmAnd/AndroidManifest.xml @@ -2,7 +2,7 @@ + android:debuggable="true" android:name=".activities.OsmandApplication" android:description="@string/app_description"> diff --git a/OsmAnd/res/layout-land/menu.xml b/OsmAnd/res/layout-land/menu.xml index 71a57f7cd1..37b2a24ea8 100644 --- a/OsmAnd/res/layout-land/menu.xml +++ b/OsmAnd/res/layout-land/menu.xml @@ -8,7 +8,7 @@ + android:background="@drawable/headliner" android:orientation="horizontal" android:id="@+id/Headliner" > + + + + + + + + + + diff --git a/OsmAnd/res/layout/menu.xml b/OsmAnd/res/layout/menu.xml index 0034f3af3e..e0a031c75e 100644 --- a/OsmAnd/res/layout/menu.xml +++ b/OsmAnd/res/layout/menu.xml @@ -8,7 +8,7 @@ + android:background="@drawable/headliner" android:orientation="horizontal" android:id="@+id/Headliner" > + На масштабе {0} загрузить {1} тайлов ({2} Mb ) + Загрузить карту + Выберите максимальный масштаб для загрузки видимой области + Выбранная карта не может быть загружена Быстрый рендеринг Выберите способ как отрисовывать карту Во время отображения карты произошла непредвиденная ошибка diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index e728e7cd0e..8ec97b1373 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -1,5 +1,10 @@ + At zoom {0} download {1} tiles ({2} Mb ) + Download map + Select max zoom to preload visible area + This map could not be downloaded + Continuous rendering Choose show continuous rendering or whole image Error occurred while rendering selected area diff --git a/OsmAnd/src/net/osmand/ResourceManager.java b/OsmAnd/src/net/osmand/ResourceManager.java index f05c701b94..a08e44debc 100644 --- a/OsmAnd/src/net/osmand/ResourceManager.java +++ b/OsmAnd/src/net/osmand/ResourceManager.java @@ -656,6 +656,10 @@ public class ResourceManager { closeTransport(); } + public synchronized void reloadTilesFromFS(){ + imagesOnFS.clear(); + } + /// On low memory method /// public void onLowMemory() { log.info("On low memory : cleaning tiles - size = " + cacheOfImages.size()); //$NON-NLS-1$ diff --git a/OsmAnd/src/net/osmand/TransportIndexRepositoryBinary.java b/OsmAnd/src/net/osmand/TransportIndexRepositoryBinary.java index dd758bdf2a..3a744d4e1a 100644 --- a/OsmAnd/src/net/osmand/TransportIndexRepositoryBinary.java +++ b/OsmAnd/src/net/osmand/TransportIndexRepositoryBinary.java @@ -96,7 +96,7 @@ public class TransportIndexRepositoryBinary implements TransportIndexRepository for(int r : stop.getReferencesToRoutes()) { try { TransportRoute route = file.getTransportRoute(r); - res.add(f.format(new String[] { route.getRef(), route.getType(), route.getName(), route.getEnName()})); + res.add(f.format(new String[] { route.getRef()+"", route.getType()+"", route.getName()+"", route.getEnName()+""})); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } catch (IOException e) { log.error("Disk error ", e); //$NON-NLS-1$ } diff --git a/OsmAnd/src/net/osmand/activities/DownloadIndexActivity.java b/OsmAnd/src/net/osmand/activities/DownloadIndexActivity.java index 620fc65806..3d465a1211 100644 --- a/OsmAnd/src/net/osmand/activities/DownloadIndexActivity.java +++ b/OsmAnd/src/net/osmand/activities/DownloadIndexActivity.java @@ -629,6 +629,7 @@ public class DownloadIndexActivity extends ListActivity { if (lowerCase.contains("map")) { //$NON-NLS-1$ if (!f) { s += ", "; //$NON-NLS-1$ + } else { f = false; } s += getString(R.string.map_index); @@ -636,6 +637,7 @@ public class DownloadIndexActivity extends ListActivity { if (lowerCase.contains("transport")) { //$NON-NLS-1$ if (!f) { s += ", "; //$NON-NLS-1$ + } else { f = false; } s += getString(R.string.transport); @@ -643,6 +645,7 @@ public class DownloadIndexActivity extends ListActivity { if (lowerCase.contains("address")) { //$NON-NLS-1$ if (!f) { s += ", "; //$NON-NLS-1$ + } else { f = false; } s += getString(R.string.address); diff --git a/OsmAnd/src/net/osmand/activities/DownloadTilesDialog.java b/OsmAnd/src/net/osmand/activities/DownloadTilesDialog.java new file mode 100644 index 0000000000..3da1322713 --- /dev/null +++ b/OsmAnd/src/net/osmand/activities/DownloadTilesDialog.java @@ -0,0 +1,235 @@ +package net.osmand.activities; + +import java.text.MessageFormat; +import java.util.ArrayList; + +import net.osmand.LogUtil; +import net.osmand.R; +import net.osmand.ResourceManager; +import net.osmand.data.preparation.MapTileDownloader; +import net.osmand.data.preparation.MapTileDownloader.DownloadRequest; +import net.osmand.data.preparation.MapTileDownloader.IMapDownloaderCallback; +import net.osmand.map.ITileSource; +import net.osmand.osm.MapUtils; +import net.osmand.views.OsmandMapTileView; + +import org.apache.commons.logging.Log; + +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.app.AlertDialog.Builder; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Rect; +import android.graphics.RectF; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.SeekBar; +import android.widget.TextView; +import android.widget.Toast; + +public class DownloadTilesDialog { + + + private final static Log log = LogUtil.getLog(DownloadTilesDialog.class); + private final Context ctx; + private final OsmandApplication app; + private final OsmandMapTileView mapView; + + public DownloadTilesDialog(Context ctx, OsmandApplication app, OsmandMapTileView mapView){ + this.ctx = ctx; + this.app = app; + this.mapView = mapView; + } + + + public void openDialog(){ + final ITileSource mapSource = mapView.getMap(); + if(mapSource == null || !mapSource.couldBeDownloadedFromInternet()){ + Toast.makeText(ctx, R.string.maps_could_not_be_downloaded, Toast.LENGTH_SHORT).show(); + return; + } + final int max = mapSource.getMaximumZoomSupported(); + final int zoom = mapView.getZoom(); + + // calculate pixel rectangle + Rect boundsRect = new Rect(0, 0, mapView.getWidth(), mapView.getHeight()); + float tileX = (float) MapUtils.getTileNumberX(zoom, mapView.getLongitude()); + float tileY = (float) MapUtils.getTileNumberY(zoom, mapView.getLatitude()); + float w = mapView.getCenterPointX(); + float h = mapView.getCenterPointY(); + RectF tilesRect = new RectF(); + final RectF latlonRect = new RectF(); + mapView.calculateTileRectangle(boundsRect, w, h, tileX, tileY, tilesRect); + + latlonRect.top = (float) MapUtils.getLatitudeFromTile(zoom, tilesRect.top); + latlonRect.left = (float) MapUtils.getLongitudeFromTile(zoom, tilesRect.left); + latlonRect.bottom = (float) MapUtils.getLatitudeFromTile(zoom, tilesRect.bottom); + latlonRect.right = (float) MapUtils.getLongitudeFromTile(zoom, tilesRect.right); + + Builder builder = new AlertDialog.Builder(ctx); + LayoutInflater inflater = (LayoutInflater)ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View view = inflater.inflate(R.layout.download_tiles, null); + + + + ((TextView)view.findViewById(R.id.MinZoom)).setText(zoom+""); //$NON-NLS-1$ + ((TextView)view.findViewById(R.id.MaxZoom)).setText(max+""); //$NON-NLS-1$ + final SeekBar seekBar = (SeekBar) view.findViewById(R.id.ZoomToDownload); + seekBar.setMax(max - zoom); + seekBar.setProgress((max - zoom) / 2); + + final TextView downloadText = ((TextView) view.findViewById(R.id.DownloadDescription)); + final String template = ctx.getString(R.string.tiles_to_download_estimated_size); + + + updateLabel(zoom, latlonRect, downloadText, template, seekBar.getProgress()); + seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){ + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + updateLabel(zoom, latlonRect, downloadText, template, progress); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + } + + }); + + builder.setPositiveButton(R.string.download_files, new DialogInterface.OnClickListener(){ + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + run(zoom, seekBar.getProgress(), latlonRect, mapSource); + } + }); + builder.setNegativeButton(R.string.default_buttons_cancel, null); + builder.setView(view); + builder.show(); + } + + private volatile boolean cancel = false; + + public void run(final int zoom, final int progress, final RectF latlonRect, final ITileSource map){ + cancel = false; + int numberTiles = 0; + for (int z = zoom; z <= progress + zoom; z++) { + int x1 = (int) MapUtils.getTileNumberX(z, latlonRect.left); + int x2 = (int) MapUtils.getTileNumberX(z, latlonRect.right); + int y1 = (int) MapUtils.getTileNumberY(z, latlonRect.top); + int y2 = (int) MapUtils.getTileNumberY(z, latlonRect.bottom); + numberTiles += (x2 - x1 + 1) * (y2 - y1 + 1); + } + final ProgressDialog progressDlg = new ProgressDialog(ctx); + progressDlg.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + progressDlg.setMessage(ctx.getString(R.string.downloading)); + progressDlg.setCancelable(true); + progressDlg.setMax(numberTiles); + progressDlg.setOnCancelListener(new DialogInterface.OnCancelListener(){ + + @Override + public void onCancel(DialogInterface dialog) { + cancel = true; + } + }); + + final MapTileDownloader instance = MapTileDownloader.getInstance(); + + final ArrayList previousCallbacks = + new ArrayList(instance.getDownloaderCallbacks()); + instance.getDownloaderCallbacks().clear(); + instance.addDownloaderCallback(new IMapDownloaderCallback(){ + @Override + public void tileDownloaded(DownloadRequest request) { + progressDlg.setProgress(progressDlg.getProgress() + 1); + } + }); + + Runnable r = new Runnable(){ + @Override + public void run() { + int requests = 0; + int limitRequests = 50; + try { + ResourceManager rm = app.getResourceManager(); + for (int z = zoom; z <= zoom + progress && !cancel; z++) { + int x1 = (int) MapUtils.getTileNumberX(z, latlonRect.left); + int x2 = (int) MapUtils.getTileNumberX(z, latlonRect.right); + int y1 = (int) MapUtils.getTileNumberY(z, latlonRect.top); + int y2 = (int) MapUtils.getTileNumberY(z, latlonRect.bottom); + for (int x = x1; x <= x2 && !cancel; x++) { + for (int y = y1; y <= y2 && !cancel; y++) { + String tileId = rm.calculateTileId(map, x, y, z); + if (rm.tileExistOnFileSystem(tileId, map, x, y, z)) { + progressDlg.setProgress(progressDlg.getProgress() + 1); + } else { + rm.getTileImageForMapSync(tileId, map, x, y, z, true); + requests++; + } + if (!cancel) { + if (requests >= limitRequests) { + requests = 0; + + while (instance.isSomethingBeingDownloaded()) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + throw new IllegalArgumentException(e); + } + } + } + } + } + } + + } + if(cancel){ + instance.refuseAllPreviousRequests(); + } else { + while (instance.isSomethingBeingDownloaded()) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + throw new IllegalArgumentException(e); + } + } + } + mapView.refreshMap(); + } catch (Exception e) { + log.error("Exception while downloading tiles ", e); //$NON-NLS-1$ + instance.refuseAllPreviousRequests(); + } finally { + instance.getDownloaderCallbacks().clear(); + instance.getDownloaderCallbacks().addAll(previousCallbacks); + app.getResourceManager().reloadTilesFromFS(); + } + progressDlg.dismiss(); + } + + }; + + + + new Thread(r, "Downloading tiles").start(); //$NON-NLS-1$ + progressDlg.show(); + } + + + private void updateLabel(final int zoom, final RectF latlonRect, final TextView downloadText, final String template, int progress) { + int numberTiles = 0; + for (int z = zoom; z <= progress + zoom; z++) { + int x1 = (int) MapUtils.getTileNumberX(z, latlonRect.left); + int x2 = (int) MapUtils.getTileNumberX(z, latlonRect.right); + int y1 = (int) MapUtils.getTileNumberY(z, latlonRect.top); + int y2 = (int) MapUtils.getTileNumberY(z, latlonRect.bottom); + numberTiles += (x2 - x1 + 1) * (y2 - y1 + 1); + } + downloadText.setText(MessageFormat.format(template, (progress + zoom)+"", //$NON-NLS-1$ + numberTiles, (double)numberTiles*12/1000)); + } +} diff --git a/OsmAnd/src/net/osmand/activities/MainMenuActivity.java b/OsmAnd/src/net/osmand/activities/MainMenuActivity.java index dc68890ec4..0749ba442c 100644 --- a/OsmAnd/src/net/osmand/activities/MainMenuActivity.java +++ b/OsmAnd/src/net/osmand/activities/MainMenuActivity.java @@ -88,9 +88,9 @@ public class MainMenuActivity extends Activity { } } - public Animation getAnimation(boolean left){ - Animation anim = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_SELF, left ? -1 : 1, - TranslateAnimation.RELATIVE_TO_SELF, 0, TranslateAnimation.RELATIVE_TO_SELF, 0, TranslateAnimation.RELATIVE_TO_SELF, 0); + public Animation getAnimation(int left, int top){ + Animation anim = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_SELF, left, + TranslateAnimation.RELATIVE_TO_SELF, 0, TranslateAnimation.RELATIVE_TO_SELF, top, TranslateAnimation.RELATIVE_TO_SELF, 0); anim.setDuration(700); anim.setInterpolator(new AccelerateInterpolator()); return anim; @@ -102,16 +102,18 @@ public class MainMenuActivity extends Activity { requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.menu); + View head = (View) findViewById(R.id.Headliner); + head.startAnimation(getAnimation(0, -1)); View leftview = (View) findViewById(R.id.MapButton); - leftview.startAnimation(getAnimation(true)); + leftview.startAnimation(getAnimation(-1, 0)); leftview = (View) findViewById(R.id.FavoritesButton); - leftview.startAnimation(getAnimation(true)); + leftview.startAnimation(getAnimation(-1, 0)); View rightview = (View) findViewById(R.id.SettingsButton); - rightview.startAnimation(getAnimation(false)); + rightview.startAnimation(getAnimation(1, 0)); rightview = (View) findViewById(R.id.SearchButton); - rightview.startAnimation(getAnimation(false)); + rightview.startAnimation(getAnimation(1, 0)); final TextView textView = (TextView) findViewById(R.id.TextVersion); textView.setText(Version.APP_VERSION+ " "+ Version.APP_DESCRIPTION); //$NON-NLS-1$ diff --git a/OsmAnd/src/net/osmand/activities/MapActivity.java b/OsmAnd/src/net/osmand/activities/MapActivity.java index cf1e7ca755..8c6c61d08f 100644 --- a/OsmAnd/src/net/osmand/activities/MapActivity.java +++ b/OsmAnd/src/net/osmand/activities/MapActivity.java @@ -1554,6 +1554,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso actions.add(resources.getString(R.string.context_menu_item_create_poi)); actions.add(resources.getString(R.string.context_menu_item_open_bug)); actions.add(resources.getString(R.string.context_menu_item_update_map)); + actions.add(resources.getString(R.string.context_menu_item_download_map)); builder.setItems(actions.toArray(new String[actions.size()]), new DialogInterface.OnClickListener(){ @Override @@ -1587,6 +1588,10 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso osmBugsLayer.openBug(MapActivity.this, getLayoutInflater(), mapView, latitude, longitude); } else if(which == 7){ reloadTile(mapView.getZoom(), latitude, longitude); + } else if(which == 8){ + DownloadTilesDialog dlg = new DownloadTilesDialog(MapActivity.this, + (OsmandApplication) getApplication(), mapView); + dlg.openDialog(); } } });