package net.osmand.plus.activities; import java.text.MessageFormat; import java.util.ArrayList; import net.osmand.LogUtil; 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.plus.R; import net.osmand.plus.ResourceManager; import net.osmand.plus.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<IMapDownloaderCallback> previousCallbacks = new ArrayList<IMapDownloaderCallback>(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)); } }