I'll be doing an app for my thesis. My thesis is a Offline Map which includes landmarks/routing. My thesis Maps is only for my City here in the philippines. I tried to use OSMDroid and failed to produce the wanted result.
What I want is (if possible) I want this to happen in my app:
Install APK
Prompt the user which country he/she wants to use
Download the chosen country for offline use.
Done
Here's my code in OSMDroid
public class MainActivity extends Activity {
public static final GeoPoint myCity = new GeoPoint(14.54321,120.23451);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MapView mapView = (MapView) findViewById(R.id.map);
mapView.setClickable(true);
mapView.setBuiltInZoomControls(true);
mapView.setMultiTouchControls(true);
mapView.setUseDataConnection(true);
mapView.setTileSource(TileSourceFactory.MAPQUESTOSM);
IMapController mapViewController = mapView.getController();
mapViewController.setZoom(13);
mapViewController.setCenter(myCity);
}
}
Here's what I've done:
I Use Mobac to a portion of the map
Save it to my Internal Phone Memory(i named it MapquestOSM)
Run the program
But when I run the program it's just Blank.
I Don't Mind using OSMDroid again as long as it will produce the same result.
I'm willing to bet you didn't do anything to tell osmdroid that you want a different map source. Here's a few pointers to help
if you use mobac to create a zip file, it source names have to match. i.e. if you get Mapnik tiles, then use the Mapnik tile source in osmdroid. Mapquest tiles, mapquest source.
zip files have an upper limit in android, use sqlite instead (also head the first point).
tell the MapView you want offline maps (setUseDataconnection(false);)
If you still have issues (and are using zip files) try altering the contents of the zip to have the first directory = Mapnik. Then using the default tile source in osmdroid.
Until my PR gets merged (to switch tile providers at runtime) and a new release cut, that's really your only option.
Edit: osmdroid only looks in /sdcard/osmdroid/ for map tiles.
Related
I'm looking for an example on how to display points of interest (saved in fusion tables) on a google map.
To do this in html and javascript it's quite trivial, check my javascript map with fusion tables example
See Fusion Tables page containing my POIs
My goal/question is how (need help in coding it) to achieve the same in an Android app. I'm new to android development and I already invested hours for the basics and checking documentation and examples.
Check this very good Google Maps example for Android I've found to get started (my test app is based on this code).
Fusion Tables v2 reference (points to google api client)
Google API Java client samples on github (most outdated: examples on v1)
So far I achieved to display a map centered on my last known location and to show a marker on it.
Because I couldn't find good examples for this, I decided to publish and share my findings, see: firepol / android-google-maps-fusion-tables on github
Now I'd like to show markers coming from fusion tables.
I'm stuck at executing the request, which I try to do via google api client.
Google API client example for Android
ActivityFeed feed = listActivities.execute();
Here my code (which I've put inside onCreate):
protected void prepareFusion() {
// Normally READONLY should be enough (see credential with one scope), but I checked online a console
// and I could see a public table only if I would grant both permissions
List<String> scopes = new ArrayList<>(Arrays.asList(FusiontablesScopes.FUSIONTABLES, FusiontablesScopes.FUSIONTABLES_READONLY));
credential = GoogleAccountCredential.usingOAuth2(this, scopes);
//credential = GoogleAccountCredential.usingOAuth2(this, Collections.singleton(FusiontablesScopes.FUSIONTABLES_READONLY));
// TODO : get account name automatically
// http://stackoverflow.com/questions/35789071/getting-the-gmail-id-of-the-user-in-android-6-0-marshmallow
credential.setSelectedAccountName("YOUR_GOOGLE_ACCOUNT");
client = new Fusiontables.Builder(
transport, jsonFactory, credential).setApplicationName("TestMap/1.0")
.build();
try {
String tableId = "1774o_WcrqSQlepLXlz1kgH_01NpCJ-6OyId9Pm1J";
Fusiontables.Query.Sql sql = client.query().sql("SELECT FileName,Name,Location FROM " + tableId);
//sql.execute();
//java.lang.IllegalStateException: Calling this from your main thread can lead to deadlock
Fusiontables.Table.Get table = client.table().get(tableId);
table.setFields("items(FileName,Name,Location)");
//table.execute();
// TODO : can't execute like this on main thread as the documentation example "suggests"
//https://developers.google.com/api-client-library/java/google-api-java-client/android
} catch (IOException e) {
e.printStackTrace();
}
}
If I try to do the same and call sql.execute() or table.execute() I get:
java.lang.IllegalStateException: Calling this from your main thread
can lead to deadlock
So I'm kinda stuck here and I'd like to know how to proceed from somebody who has experience with the google api client, even better if you can help me to get the result on the map! Thank you.
How to display the fusion tables POIs on the map?
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// Add a marker to Zurich Oerlikon and move the camera
mMap.addMarker(new MarkerOptions().position(mDefaultLatLng).title("Zurich Oerlikon"));
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(
mDefaultLatLng, 13));
// TODO: add fusion tables POIs
}
To see where I'm stuck and help me, clone my github repo firepol / android-google-maps-fusion-tables on github, open it in Android Studio, add your own Google Maps API Key and debug on your device. Thanks for your constructive comments, answers and help. Feel free to push on github as well.
In android networks calls are never made on UI/main thread.
Try using an async task if you just want to see things working or import a networking library like volley/robospice if you are developing a full project.
This commit implements the fusion tables query and shows the resulting POIs on google maps
Explanation: GoogleAccountCredential was wrong and had to be replaced with GoogleCredential. To make this work you need to create a service account, role project > service account actor (generate a private key), download the json file and place it under app/res/raw/service_account_credentials.json (in my commit I refer to this file with this precise name, but feel free to raname it and adapt the code to your needs).
Make sure to enable the Fusion Tables API in the API Manager for your project.
I implemented also a class deriving from the AsyncTask to solve the problem of the main thread.
There is some little refactoring in the commit (Location changed to LatLng) but that's it.
Whoever needs to make an android app and place fusion tables POIs on a google map can clone the github repo and have something to begin with (which was also the initial idea of my question).
This might be a very naive question but I can't get this java.lang.Exception error to go away. I also just started learning java and android so... this might be an easy problem to solve.
So I have a main activity in android and I want to implement a weka ml classifier within the app. Right now I'm just trying to load some data.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ml_classifiers ml_object = new ml_classifiers();
int number = ml_object.loadData();
Trying to load data...
public class ml_classifiers {
public int loadData() {
ConverterUtils.DataSource source = new ConverterUtils.DataSource("C:/Users/Seth/Desktop/iris.arff");
Instances data = source.getDataSet();
int num = data.numInstances();
return num;
}
}
Why does java.lang.exception occur?
Why does java.lang.exception occur?
In the future, when you encounter crashes, use LogCat to examine the Java stack trace associated with the crash. If you do not understand the stack trace or otherwise cannot identify the problem, and you want help here, post the stack trace along with the code. As it stands, we have to guess exactly what is going wrong in your app.
In this case, while you may be crashing elsewhere, you will definitely crash with:
ConverterUtils.DataSource source = new ConverterUtils.DataSource("C:/Users/Seth/Desktop/iris.arff");
assuming that this is code in your Android app.
You are attempting to read data from C:/Users/Seth/Desktop/iris.arff. That is a path to a file on a Windows machine. Android is not Windows. There are ~2 billion Android devices in use, and none of them have access to files on your Windows' machine's desktop.
You need to get this data onto the Android device, such as:
by putting it in the assets/ directory in your module (to package it with your app), then using AssetManager to get an InputStream on that asset, hopefully passing that directly to ConverterUtils.DataSource
downloading the file from the Internet, perhaps into internal storage (e.g., getCacheDir())
expecting the user to copy the file onto their device by hand, such as via external storage
I've written an Android app that is a simpler version of the stock camera. It only records video.
Despite this being a custom app, I'd like to have the videos recorded by this be easily visible from the Photos and Gallery apps.
I was under the impression that this is what the "MediaScannerConnection" class is for. I've found common advice that shows how to use this in either a "sendBroadcast" mode, or a more manual "scanFile" approach. I've implemented both of these options and found that they appear to have no effect. When I stop the recorder, a valid video is stored (I can play it from a file browser afterwards), but neither Photos or Gallery is made aware of the new video.
I've been storing the videos in files like "/storage/emulated/0/DCIM/Camera/20151223_150115.mp4". That directory also contains videos taken by the stock camera app. The base path was obtained from "Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)". I originally tried replacing "Camera" with a directory name based on the name of my app, but as that wasn't working (Photos/Gallery not seeing it, despite it being stored properly), I decided to try storing them where the stock videos are stored. That isn't working either.
My test device is a Galaxy Note 3, running Android 5.0.
My first attempt at using MediaScannerConnection was with this:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + outputFilePath)));
One of the values of "outputFilePath" is exactly the path shown above.
As this didn't appear to do anything, I then later tried this:
new SingleMediaScanner(getApplicationContext(), new File(outputFilePath));
Where "SingleMediaScanner" is this:
public static class SingleMediaScanner implements MediaScannerConnection.MediaScannerConnectionClient {
private MediaScannerConnection mMs;
private File mFile;
public SingleMediaScanner(Context context, File f) {
mFile = f;
mMs = new MediaScannerConnection(context, this);
mMs.connect();
}
#Override
public void onMediaScannerConnected() {
mMs.scanFile(mFile.getAbsolutePath(), "image/*");
}
#Override
public void onScanCompleted(String path, Uri uri) {
mMs.disconnect();
}
}
I tried running the last implementation in the debugger, and I saw it get to "onScanCompleted", but neither of the aforementioned apps see the new video.
Update:
With the current implementation, the "onScanCompleted" callback method gets called with "path" and "uri" parameters, which have the following values:
path: /storage/emulated/0/DCIM/Camera/20151223_194434.mp4
uri.toString(): content://media/external/file/106639
Uri.fromFile(new File(Path)): file:///storage/emulated/0/DCIM/Camera/20151223_194434.mp4
I'm basically writing my first hello world in android studio and the java file says that the xml layout file and other resources in the res file don't exist. I took the references to these things from books/tutorials so they should work.
The book said to use
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main.xml);
}
But when that didn't work I changed it to res.layout.activity_main.xml
my project directory looks like this
How do I make it work?
http://i.stack.imgur.com/N71sl.png
//EDIT
http://i.stack.imgur.com/HUgsm.png
You are referencing res not R.
do something like this: setContentView( R.layout.activity_main);
Leave off the ".xml"
update your android studio in stable channel and restart android studio and build the project again .
You need to understand the concept of the R class in android.
The R class is auto generated every time you build your project and cannot be modified.
This class contains a map of all the projects assets. Every time you created or import a resource, set a dimension, a string, create a layout, add or change id etc. the R file is changed in the background.
So if you want to access a resource you simply call it using the R class.
For example:
layout: R.layout.activity_main
string: R.string.hello_world
id: R.id.et_main_helloWorld
And so on.
More info can be found here.
Make sure you also check Providing Resources and Accessing Resources for a better understanding.
Good luck and happy coding.
In the end I started a new project and added in everything piece by piece, I had put a mp3 file in the values directory which was messing up the R file.
I'm using Cordova v4.1.2. The app uses media volume by default, and I want it to use the ringer volume for the sounds it plays. (Like in WhatsApp)
I used setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);in the onCreate() function. But it gives an error.
This is my CordovaApp.java. (in platforms\android\src\com\XX\XX)
import android.os.Bundle;
import org.apache.cordova.*;
public class CordovaApp extends CordovaActivity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.init();
// Set by <content src="index.html" /> in config.xml
loadUrl(launchUrl);
setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
}
}
It shows the following error on running:
There is no error when I remove the line setVolumeControlStream(AudioManager.STREAM_VOICE_CALL); from the java file, and the app runs perfectly. Any views on how to fix this?
Fixed it myself. Really easy if you were an Android geek, but anyways such a question was never asked before so I'll post the answer for others running into this same trouble.
I was right in changing the audio stream, but I was changing that in the wrong file! Doh!
This is where you should change it..
\platforms\android\CordovaLib\src\org\apache\cordova\CordovaActivity.java
at line 351 change it to setVolumeControlStream(AudioManager.STREAM_RING);
If you want to use the ringer volume though.
If you build and press the hardware volume keys, it will change and appear to use the ringer volume of course. But my case was a bit different.
I was using the cordova Media plugin org.apache.cordova.media. So when I play an audio using this plugin, it re-wires the stream back to media stream (STREAM_MUSIC). I was back to ground zero. The idea is to re-wire the plugin itself to use the audio stream of your choice. No rocket science, just change 2 lines in 2 files.
File:
\platforms\android\src\org\apache\cordova\media\AndroidHandler.java
Line 383:
setVolumeControlStream(AudioManager.STREAM_RING);
File:
\platforms\android\src\org\apache\cordova\media\AudioPlayer.java
Line 526:
setVolumeControlStream(AudioManager.STREAM_RING);
And you're good to go. Remember to replace STREAM_RING with your desired audio stream.