minhld / osmdroid

Automatically exported from code.google.com/p/osmdroid
0 stars 0 forks source link

Unable to use MOBAC created OSMAND SQLite tile source offline #386

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
What steps will reproduce the problem?
Unable to load the attached OSMAND SQLite map tiles. (GeoPoint((int)(45.349622 
* 1E6), (int)(-75.880700 *1E6)) can be used to center within the map tile area) 
Source included below. Can't locate any official documentation on how to do so, 
just blog posts that differ in their approach and none seem to work for me.

What is the expected output? What do you see instead?
I want to load map tiles from a MOBAC SQLite. See my explanation below.

What version of the product are you using? On what operating system?
OSMDROID 3.0.8
Android stock 4.2 (targeting 2.3.3, testing in emulator an on 4.2 device for 
now)

Please provide any additional information below.

I've been pulling my hair out trying to get my own offline Mobile Atlas Creator 
OSMAND SQLite map working with OSMDROID 3.0.8 without luck. It's been a long 3 
days. I'll try to explain with clips from my application. I've been extending 
ItemizedIconOverlay and OverlayItem so I hope it doesn't get too confusing.

I created my own OSMAND SQLite map file with 3 different zoom levels for a 
small are, like 10 square kms. I copied the resulting "base.sqlite" file into 
my project /res/raw/ directory. Note that the GeoPoints in my application 
should be well within the map's tile range. The "base.sqlite" file should get 
saved to the application specific data directory.

Next I turfed the /osmdroid directory on my phone so I could get the previously 
cached maps off. I thought I had my own offline maps working until I turned on 
Airplane mode and noticed the cached maps were still available.

Now all I get is blanks. I have no clue how to get this going. I've see a 
couple of examples but after a ton of experimentation I haven't been successful 
in getting any of them working.

    private Hashtable<String, NodeOverlayItem> nodes = new Hashtable<String, NodeOverlayItem>();

    private MapView mapView;
    private Context context;

    private LocationManager locManager;

    private MapController mapController;
    private MapTileProviderArray mapProvider;
    private String mapTileArchivePath = "base.sqlite";

    private ResourceProxy resourceProxy;

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        try {
            this.mapView = new MapView(this, 256);
            this.mapView.setBuiltInZoomControls(true);
            this.mapView.setMultiTouchControls(true);

            this.context = this.getApplicationContext();
            this.resourceProxy = new DefaultResourceProxyImpl(context);

            XYTileSource TILERENDERER = new XYTileSource("test", 
                ResourceProxy.string.offline_mode, 
                1, 20, 256, ".png", "http://127.0.0.1");
            SimpleRegisterReceiver simpleReceiver = new SimpleRegisterReceiver(this.context);

            IArchiveFile[] archives = { ArchiveFileFactory.getArchiveFile(this.getMapsFile()) };
            MapTileModuleProviderBase moduleProvider = new MapTileFileArchiveProvider(
                    simpleReceiver, 
                    TILERENDERER, 
                    archives);
            this.mapProvider = new MapTileProviderArray(TILERENDERER, null, new MapTileModuleProviderBase[] { moduleProvider });
            this.mapProvider.setUseDataConnection(false);
            this.mapView = new MapView(this, 256, this.resourceProxy, this.mapProvider);
            this.mapView.setUseDataConnection(false);

            mapController = mapView.getController();
            mapController.setZoom(18);
            mapController.setCenter(new GeoPoint((int)(45.349622 * 1E6), (int)(-75.880700 *1E6)));

            this.setContentView(mapView);
        } catch(Exception ex) {
            Log.e("test", ex.getMessage());
        }    
    }

    public File getMapsFile() throws IOException {
        Log.d("test", "Trying to load map tiles to: " + this.mapTileArchivePath);
        FileOutputStream fos = this.openFileOutput(this.mapTileArchivePath, Context.MODE_PRIVATE);

        InputStream in = getResources().openRawResource(R.raw.osmdroid);
        byte[] buff = new byte[1024];
        int read = 0;
        try {
        while ((read = in.read(buff)) > 0) {
          fos.write(buff, 0, read);
        }
        } finally {
          in.close();
          fos.close();
        }
        return new File(this.getFilesDir(), this.mapTileArchivePath);
        }

Original issue reported on code.google.com by ch...@mckenzieic.com on 11 Dec 2012 at 7:42

Attachments:

GoogleCodeExporter commented 8 years ago
The sqlite archive format was added in revision 683 for issue 132.

Original comment by neilboyd on 12 Dec 2012 at 6:30

GoogleCodeExporter commented 8 years ago
I think what I'm saying is it's not clear how to properly load MOBAC OSMAND 
SQLite tiles and I'd like to know how to do so properly. Other have been asking 
this as well:

http://stackoverflow.com/questions/13827324/how-to-use-mobac-created-osmand-sqli
te-tile-source-file-offline
http://stackoverflow.com/questions/12968594/downloading-specific-maptiles-to-cac
he-in-osmdroid

As you can see in my sample code, I'm already using ArchiveFileFactory, which 
indeed supports a variety of archive file types, including sqlite. The tiles 
are still coming up empty.

Can you please comment on my use of MapTileModuleProviderBase, MapView, 
MapTileFileArchiveProvider and SimpleRegisterReceiver? Am I using it right? Do 
you have an existing sample on how to do this properly with the API? If I'm 
doing it right, then I should probably investigate if my MOBAC map has an 
issue. BTW, I'm using the latest MOBAC, downloaded 5 days ago. Thank you!

Original comment by ch...@mckenzieic.com on 12 Dec 2012 at 3:57

GoogleCodeExporter commented 8 years ago
In issue 132 which I linked to in my previous comment it says "you have to 
chose the osmdroid sqlite format".

I assume that osmdroid sqlite format is different to osmand sqlite format.

Original comment by neilboyd on 12 Dec 2012 at 8:26

GoogleCodeExporter commented 8 years ago
Arg... Sorry that was a persistent typo. I've reattached a fresh MOBAC exported 
Osmdroid sqlite map file. I'm still getting grey squares.

Now, can you please comment on my use of MapTileModuleProviderBase, MapView, 
MapTileFileArchiveProvider and SimpleRegisterReceiver?

Thank you.

Original comment by ch...@mckenzieic.com on 12 Dec 2012 at 11:30

Attachments:

GoogleCodeExporter commented 8 years ago
Ok, my usage is good. I don't know exactly what my problem was, but I had some 
trouble with the osmdroid sqllite file written to the device. I ended up 
getting the zip format working. Just a suggestion, a small offline mapping 
sample would be really helpful. Maybe I'm just over worked or lazy. Either way 
I've got offline working perfectly now. Thanks for being patent with me. :)

Original comment by ch...@mckenzieic.com on 14 Dec 2012 at 6:25

GoogleCodeExporter commented 8 years ago
Kinda late, but is it still possible for you to provide your solution?
Would be really helpfull, thanks :)

Original comment by stefan.e...@gmail.com on 2 Jul 2013 at 1:19

GoogleCodeExporter commented 8 years ago
Sure, I'm not certain anymore what exactly was going wrong at the time, but 
here's my implementation of the MapView. From what I've come up with, you can't 
set and offline MapView outside of its construction. Meaning you have to 
construct the MapView with a provided MapTileProviderArray that includes the 
offline source. e.g. .zip or .sqlite file. I can't remember why this was an 
issue for me in my actual application. I think I was having problems with app 
orientation change. Since MapView is a valid View, it get constructed without 
your help by Android. In order to construct it with my offline provider, I had 
to extend MapView with my own constructor, that created and supplied the 
offline provider.

So far my app seems to have no issues with this approach. It loads the maps 
correctly and I don't get any orientation change memory leaks/errors when I 
flip my tablet a dozen times or so.

Hope this helps.

MainActivity.java:
    @Override
    public void onCreate(final Bundle savedInstanceState) {
        try {
            super.onCreate(savedInstanceState);
            ...

            this.mapView = (FieldMapView) findViewById(R.id.mapview);
            ...
            // Example getting the map controller and setting the center
            MapController mapController = this.mapView.getController();
            mapController.setCenter(new GeoPoint(Nodes.LAT_DEFAULT, Nodes.LONG_DEFAULT));
            ...
    }

    public static String getMapTileArchiveFilename() {
        return "default_map.zip";
    }

main_activity.xml: (the layout)

    ...
    <com.test.FieldMapView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/mapview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:clickable="false"/>
    ...

com.test.FieldMapView.java:
public class FieldMapView extends MapView {
    public FieldMapView(Context context, AttributeSet attrs) throws Exception {
        // Sigh... MapView has to be constructed as an offline caching view,
        // which is the reason I've got these static calls in here...
        super(context, 256, new DefaultResourceProxyImpl(context), FieldMapView
                .getOfflineMapProvider(context, MainActivity.getMapTileArchiveFilename()), null, attrs);
        this.setUseDataConnection(false);
        this.setBuiltInZoomControls(true);
        this.setMultiTouchControls(true);
        this.setLongClickable(false);
    }

    public static MapTileProviderArray getOfflineMapProvider(Context context,
            String mapArchiveFilename) throws Exception {
        XYTileSource TILERENDERER = new XYTileSource("OSM CloudMade 1",
                ResourceProxy.string.offline_mode, 16, 18, 256, ".png",
                "http://127.0.0.1");
        SimpleRegisterReceiver simpleReceiver = new SimpleRegisterReceiver(
                context);
        IArchiveFile[] archives = { ArchiveFileFactory
                .getArchiveFile(FieldMapView.getMapsSdCard(context,
                        mapArchiveFilename)) };
        MapTileModuleProviderBase moduleProvider = new MapTileFileArchiveProvider(
                simpleReceiver, TILERENDERER, archives);
        MapTileProviderArray mapProvider = new MapTileProviderArray(
                TILERENDERER, null,
                new MapTileModuleProviderBase[] { moduleProvider });
        mapProvider.setUseDataConnection(false);
        return mapProvider;
    }

    public FieldMapView(Context context, int tileSizePixels,
            ResourceProxy resourceProxy, MapTileProviderBase aTileProvider,
            Handler tileRequestCompleteHandler) {
        super(context, tileSizePixels, resourceProxy, aTileProvider,
                tileRequestCompleteHandler);
    }

    public FieldMapView(Context context, int tileSizePixels,
            ResourceProxy resourceProxy, MapTileProviderBase aTileProvider) {
        super(context, tileSizePixels, resourceProxy, aTileProvider);
    }

    public FieldMapView(Context context, int tileSizePixels,
            ResourceProxy resourceProxy) {
        super(context, tileSizePixels, resourceProxy);
    }

    public FieldMapView(Context context, int tileSizePixels) {
        super(context, tileSizePixels);
    }

    public void onStop() {
        this.getTileProvider().clearTileCache();
    }

    // TODO: Create a factory static method to construct the FieldMapView properly, use isInEditMode()
    // to skip writing the file out, so it'll work with the Eclipse visualizer!

    public static File getMapsSdCard(Context context, String mapArchiveFilename)
            throws IOException {
        Log.d("TEC3M", "Trying to load map tiles to: " + mapArchiveFilename);
        File mapFile = new File(context.getFilesDir(), mapArchiveFilename);
        if (!mapFile.exists()) {
            // mapFile.delete();
            FileOutputStream fos = context.openFileOutput(mapArchiveFilename,
                    Context.MODE_PRIVATE);
            InputStream in = context.getResources().openRawResource(
                    R.raw.default_map);
            byte[] buff = new byte[1024];
            int read = 0;
            try {
                while ((read = in.read(buff)) > 0) {
                    fos.write(buff, 0, read);
                }
            } finally {
                in.close();
                fos.close();
            }
            mapFile = new File(context.getFilesDir(), mapArchiveFilename);
        }
        return mapFile;
    }
}

Original comment by ch...@mckenzieic.com on 2 Jul 2013 at 2:43

GoogleCodeExporter commented 8 years ago
This ticket is resolved.

Original comment by kurtzm...@gmail.com on 10 Jul 2013 at 10:08