How to create map tiles from OpenStreetMap offline, display it on Android? - java

What I want is to display a simple offline map using OpenStreetMap. I cannot find in the web the right tools to create map tiles and use it to display a map in Android. I have downloaded different resources but it seems that I don't have any idea where to start. I want to integrate images from OpenStreetMap using JOSM but i don't know if I can use it on Android.
Can I use Mapnik? Your help will a great thank you.

I'm currently developing (my first) Android application using the OpenStreetMap (OSM) API, so while I can't help you with the JSOM, I can try to help with the OSM part:
Assuming that you want to create a new activity in your android application that simply displays a OSM map, you might start with something like this:
package example.stackoverflow.osmdroid;
import android.app.Activity;
import android.os.Bundle;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
public class YourMap extends Activity {
// The MapView variable:
private MapView m_mapView;
// Default map zoom level:
private int MAP_DEFAULT_ZOOM = 15;
// Default map Latitude:
private double MAP_DEFAULT_LATITUDE = 38.535350;
// Default map Longitude:
private double MAP_DEFAULT_LONGITUDE = -121.753807;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Specify the XML layout to use:
setContentView(R.layout.osm_map);
// Find the MapView controller in that layout:
m_mapView = (MapView) findViewById(R.id.mapview);
// Setup the mapView controller:
m_mapView.setBuiltInZoomControls(true);
m_mapView.setMultiTouchControls(true);
m_mapView.setClickable(true);
m_mapView.setUseDataConnection(false);
m_mapView.getController().setZoom(MAP_DEFAULT_ZOOM);
m_mapView.getController().setCenter(
new GeoPoint(MAP_DEFAULT_LATITUDE, MAP_DEFAULT_LONGITUDE));
m_mapView.setTileSource(TileSourceFactory.MAPNIK);
} // end onCreate()
} // end class YourMap
Where your osm_map.xml layout may look something like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.osmdroid.views.MapView
android:id="#+id/mapview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:enabled="true"
android:clickable="true"
/>
</RelativeLayout>
As for the actual map tiles, there is a really cool program called Mobile Atlas Creator, which allows you to generate the necessary map tiles for the offline Android map implemented above.
Once you have the application installed, and you want to create a new atlas, you'll be asked to select your "desired altas format." When this pops up, select "Osmdroid zip."
Once everything loads, select a region on the map that you would like to create tiles for, select the zoom levels you want tiles for, and hit the "Add Selection" button in the column on the left, followed by "Create Atlas."
Oh, and depending on the source, you may need to check the "Create/Adjust Map tiles" checkbox to force the tiles to be exported as PNGs -- does anyone know if it's possible to use JPG with OSM?
Once the ZIP has been generated, I renamed it to "Mapnik.zip" and moved it to a newly created folder called "tiles" in my Eclipse Android project workspace. In order to get it working, I also had to open the zip file, and rename the top level folder from something like "Google Earth" (depending on the map source you used), to "Mapnik," in order for the tile to display in my Android application.
In order to actually load the tiles onto your phone, however, you'll need to use the ADB tool from the terminal. In your ADB tool directory, you'll want to run something like this (each line is a new command):
./adb shell rm -r /sdcard/osmdroid/
./adb shell mkdir /sdcard/osmdroi/
./adb push ~/path/to/your/mapnik.zip /sdcard/osmdroid
Depending on the size of the map and the speed of the phone's memory bus, this last step may take a several minutes to an hour to complete. Once done, your map should work -- I hope!
As I mentioned, this is the first time I've used the OSM API, so I'm by no means an expert on it, and I can only comment on what worked for me.
Hope this will help you get started!
EDIT:
I didn't have a chance to actually run the code that I wrote up yesterday, so I didn't catch a few of the errors. I just created a new project in Eclipse, dumped my code in there, fixed a few things and got it up and running. All changes that I made are reflected in the code above! I forgot several of the basic import statements, and I forgot to add permissions to the manifest.xml file.
The last few lines of my manifest.xml now look like this:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
And you also might want to add this to the manifest, although certainly not critical:
<supports-screens
android:anyDensity="true"
android:resizeable="false"
android:largeScreens="true"
android:normalScreens="true"
/>
Add this right after the <uses-sdk ... /> part.
Furthermore, be sure to import the following two JAR libraries:
osmdroid-android-3.0.3.jar // Or whatever version you're using...
and
slf4j-android-1.5.8.jar // Or whatever the latest version is...
Without this last JAR, my code kept crashing until I remembered to include it.
Make sure to modify the default coordinates so that they point to a location that you actually have map tiles for, otherwise you're not going to see much of anything, aside from a white canvas.
Sorry for not running the code on my end first!

Here is a step by step solution:
In brief:
1- You must download map tiles using Mobile Atlas Creator. I have explained the steps HERE
2- Move the resulting zip-file to /mnt/sdcard/osmdroid/ on your device.
3- Adding osmdroid-android-XXX.jar and slf4j-android-1.5.8.jar into build path your project
4- Adding MapView: You can add a MapView to your xml layout
<org.osmdroid.views.MapView
android:id="#+id/mapview"
android:layout_width="match_parent"
android:layout_height="match_parent"
tilesource="Mapnik"
/>
Or create a MapView programmatically:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
mResourceProxy = new ResourceProxyImpl(inflater.getContext().getApplicationContext());
mMapView = new MapView(inflater.getContext(), 256, mResourceProxy);
return mMapView;
}
Don't forget to add these permissions to your Manifest:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
This is a good Sample Project.
Hope it Helps ;)
Important
As #Scai mentioned: recently Open Street Map announced that this tool is not good and had some problems:
This tool results in heavy traffic for the OSM tile servers and is likely to be blocked.
Please don't use it.

Alternatively to map tiles you can also use vector data for your offline map, for example mapsforge or the Mapbox Android SDK. For more information consult the OSM wiki about offline OSM and Android libraries.

Related

File not found in sceneform 1.16

My app is not able to read/load the file from local. I am using Android Studio 4.0 and Sceneform 1.16. The code works fine if I use https path (Ex. https://storage.googleapis.com/ar-answers-in-search-models/static/Tiger/model.glb)
The problem is 'File not found' error. In the below code i have also use getApplicationContext() instead of 'this'. Problematic part
ModelRenderable.builder()
.setSource(this,Uri.parse("/sampledata/models/abc.glb") ) <--- Problem
.setIsFilamentGltf(true)
.build()
.thenAccept(......
Have added below permissions:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
Thanks for your help.
I was able to get the image through
ModelRenderable.builder()
.setSource(this,R.raw.abc)
But I am not getting the texture or material. I am exporting the image/object from blender.
Also, would like to know if uri.parse("") can work with object saved locally. The above way has its own limitations.
Not marking this as solved for now.
You can put your glb in asset directory.
And load it like below
ModelRenderable.builder().setSource(this, Uri.parse("model.glb"))
Or if your glb is saved in device storage,
ModelRenderable.builder().setSource(this, Uri.fromFile(File(YOUR_GLB_PATH)))
You can access a GLB model from assets as follows - the below example is Kotlin and is tested againstmSceneform 1.18 which is the same as Sceneform 1.16.
//Build the renderable - this uses the new to Sceneform 1.16 glb model format
val modelFilePath = getFileFromAssets(this, "yourModel.glb").absolutePath
ModelRenderable.builder()
.setSource(
this,
Uri.parse(
modelFilePath))
.setIsFilamentGltf(true)
.build()
.thenAccept(
Consumer { modelRenderable: ModelRenderable ->
//Add anything you want to do here....
Log.d(TAG,"Model loaded")
})
.exceptionally( Function<Throwable, Void?> { throwable: Throwable? ->
//Add anything you want to do here e.g.:
Log.d(TAG, "ModelRenderable.builder exception: " + throwable)
null
})

Get current location with network provider on osmdroid

In my android app I am using the osmdroid framework. In the framework I am using the MyLocationNewOverlay() which contains a method to show the current location on the map.
My problem
The LocationListener in the framework seems not to use the network provider and only wants to locate me with GPS (which works fine, but only if I am outside).
Is there a standard way to use a LocationProvider that also works with the network provider if gps is not available?
AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Pretty standard to init my location overlay:
private void initMyLocationNewOverlay() {
myLocationNewOverlay = new MyLocationNewOverlay(new GpsMyLocationProvider(context), mapView);
myLocationNewOverlay.enableMyLocation();
mapView.getOverlays().add(myLocationNewOverlay);
}
Thanks in advance!
The problem is that the GpsMyLocationProvider only adds the GPS_Provider to its sources (you can see that in the constructor). To add the network provider use the addLocationSource as following.
private void initMyLocationNewOverlay() {
GpsMyLocationProvider provider = new GpsMyLocationProvider(context);
provider.addLocationSource(LocationManager.NETWORK_PROVIDER);
myLocationNewOverlay = new MyLocationNewOverlay(provider, mapView);
myLocationNewOverlay.enableMyLocation();
mapView.getOverlays().add(myLocationNewOverlay);
}

Android In App Billing From PreferenceScreen

I have never really had to ask a question here. Almost any question I can think of has already been asked and answered. Thus the reason I have never registered.
However, I have finally run across something that I cannot find an answer for. I assume it would be fairly simple.
I am trying to implement in app billing for an android project I am working on. I typically code in C# and use Unity to build the .APK.
However, this time I have to make modifications in Eclipse to some PreferenceScreens.
I have an xml file with some string-arrays set up for a ListPreference under my PreferenceScreen. These ListPreference values are then passed to UnityPlayer for a method. That's all set up.
I am trying to figure out a way to set up in app billing to trigger on selection of one of my list preference, or preference items.
I can probably figure a lot of it out on my own, but I need help with a function to do something pulling from a string value in the list preferences. Does this make sense?
I don't expect to be spoon fed, so if I can just get help on a few lines for this I would appreciate it. Of course I won't complain if anyone wants to write up a little 20 liner function to do it for me.
Thanks in advance,
John
** edit **
Here is the xml from the preferenceScreen I need to address with android In App Billing from Java
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:key="wallpaper_settings"
android:title="#string/wallpaper_settings" >
<!-- Ad Placeholder -->
<CheckBoxPreference
android:defaultValue="true"
android:key="rotate"
android:summary="#string/rotateSummary"
android:title="#string/rotateTitle" />
<CheckBoxPreference
android:defaultValue="true"
android:key="doubleTap"
android:summary="#string/doubleTapSummary"
android:title="#string/doubleTapTitle" />
<CheckBoxPreference
android:defaultValue="false"
android:key="swipeEmul"
android:summary="#string/simulateSwipeSummary"
android:title="#string/simulateSwipeTitle" />
<ListPreference
android:entryValues="#array/cameraValues"
android:defaultValue="MainCamera"
android:entries="#array/whichCam"
android:summary="#string/cameraSummary"
android:dialogTitle="#string/cameraTitles"
android:title="#string/cameraTitles"
android:key="whichCam"/>
</PreferenceScreen>'
This question is very generic, on an Android application you might do this by creating an Activity, then starting that activity from your preference "onClick" method and then, once the activity starts, you load all your in app billing stuff (showing a progress dialog) and finally present the "buy" dialog. Is this what you need?

How to add custom view in android's JellyBean Launcher

I am working on making custom launcher in android. I have referred the code of android's Jellybean launcher. now I want to make some modification in this launcher.
What I want : As we know there are default five work-space screens and I want to add custom view in any one of the workspace screen. My xml file should be inflated in any one of the screen.
I have tried many ways to do it but as the default launcher code is very complex still having no luck to finding out way for it.
There is already app named SOHO in Playstore doing exactly what I want. I have add the screenshot for referencing what i want.
Please help me if anyone of you having any idea to do it.
I've the answer for you. You can do it both in Launcher2 and Launcher3 package from (AOSP). Jellybean is using Launcher2 may be. I personally suggest you to go with Launcher3, it has buit-in way to do so.
Launcher3:
create a class that extends the com.android.launcher3.Launcher class and override the necessary methods like so:
public class MyLauncher extends Launcher {
#Override
protected boolean hasCustomContentToLeft() {
return true;
}
#Override
protected void addCustomContentToLeft() {
View customView = getLayoutInflater().inflate(R.layout.custom, null);
CustomContentCallbacks callbacks = new CustomContentCallbacks() {
#Override
public void onShow() {}
#Override
public void onScrollProgressChanged(float progress) {}
#Override
public void onHide() {}
};
addToCustomContentPage(customView, callbacks, "custom view");
}
}
Here R.layout.custom is the custom view that you wanted.
Then in the manifest file change the launcher activity class from Launcher to MyLauncher. And that's it.
Launcher2:
in Workspace.java create the following method:
public void addCustomView(View child){
CellLayout layout = (CellLayout) getChildAt(0);
layout.addView(child);
}
then in Launcher.java, find the following line:
mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);
then paste the following code somewhere after that line:
View child = LayoutInflater.from(this).inflate(R.layout.custom, null);
mWorkspace.addCustomView(child);
If I remember correctly you just need to implement a standard activity which displays a home launcher. In your Manifest.xml you just need to define it like this:
<activity android:name=".YourLauncher" android:label="#string/launcher_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
you can simply add view in default lanucher use code
wm = (WindowManager) getSystemService("window");
params = new LayoutParams();
params.type = LayoutParams.TYPE_PHONE;
params.format = PixelFormat.RGBA_8888;
params.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
| LayoutParams.FLAG_NOT_FOCUSABLE;
params.x = 100;
params.y = 100;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.gravity = Gravity.LEFT | Gravity.TOP;
wm.addView(view, params);
when you want to remove it
just
wm.removeView(v);
you also need permission
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Good news, not so good news, bad news. Good new first.
It is possible to do what you want.
Now the not so good news.
You will have to write the launcher application from scratch(aka Home Screen). Yep, that involves doing all those nice and nifty things that the default launcher does(multiple pages, drag and drop, delete/add app icons, etc). Fortunately, its not as difficult as it sounds. Because the default launcher app itself is opensource. Though this code is complete, its not easy to read. A easier place to start would be the SDK
Android-SDK/samples/android-x/Home/
where x is the API level.
They have provided source code for an example home screen and it should give you a good start. With some perseverance and coffee, you should be able to modify the Launcher2 code to add a customized page of your own.
Now the Hard part.
Because a part of your goal is to keep the existing pages same and add a new page, getting this to work for all the flavors of android... HTC sense, Samsung TouchWiz, etc, etc is not a single person workload. They all have different features for the Home screen. Preserving these features and adding a new customized page is a tough task.

Obtaining Phone number

I am trying to get the user's phone number but the problem is that I am getting null response
based on my research so far we can get the same by using the object of TelePhony Manager and calling function getLine1Number()
but I am not getting any response,somebody suggested that this is because the service provider is not providing the same in my country I am in India but for blackberry it's providing the phone number so what could be the possible problem please suggest my whole algo depends on this.
Have you added the permission
<uses-permission android:name="android.permission.READ_PHONE_STATE">
</uses-permission>
to your AndroidManifest.xml file?
have you tried using
String phoneNumber = extras.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
If you have already used this, I will recommend that you elaborate your question in a more specific way.
Add this permission to your android manifest file
<uses-permission android:name="android.permission.READ_PHONE_STATE">
</uses-permission>
use following code to get number
number = extras.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);

Categories