Osmdroid 5.6, offline MBTiles - osmdroid

I'm trying to use MBtiles offline with osmdroid,
I took code sample from here https://github.com/osmdroid/osmdroid/blob/master/OpenStreetMapViewer/src/main/java/org/osmdroid/samplefragments/tileproviders/SampleOfflineOnly.java
But always empty map shown, is there problem with my code?
my code is:
public class OSMDroid extends AppCompatActivity {
private MapView mapView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_osmdroid);
mapView = (MapView) findViewById(R.id.map);
String name = "map.mbtiles";
File f = new File(Environment.getExternalStorageDirectory() + "/osmdroid", name);
if (f.exists()) {
try {
//ok found a file we support and have a driver for the format, for this demo, we'll just use the first one
//create the offline tile provider, it will only do offline file archives
//again using the first file
OfflineTileProvider tileProvider = new OfflineTileProvider(new SimpleRegisterReceiver(this),
new File[]{f});
//tell osmdroid to use that provider instead of the default rig which is (asserts, cache, files/archives, online
mapView.setTileProvider(tileProvider);
//this bit enables us to find out what tiles sources are available. note, that this action may take some time to run
//and should be ran asynchronously. we've put it inline for simplicity
String source = "";
IArchiveFile[] archives = tileProvider.getArchives();
if (archives.length > 0) {
//cheating a bit here, get the first archive file and ask for the tile sources names it contains
Set<String> tileSources = archives[0].getTileSources();
//presumably, this would be a great place to tell your users which tiles sources are available
if (!tileSources.isEmpty()) {
//ok good, we found at least one tile source, create a basic file based tile source using that name
//and set it. If we don't set it, osmdroid will attempt to use the default source, which is "MAPNIK",
//which probably won't match your offline tile source, unless it's MAPNIK
source = tileSources.iterator().next();
mapView.setTileSource(FileBasedTileSource.getSource(source));
} else {
mapView.setTileSource(TileSourceFactory.DEFAULT_TILE_SOURCE);
}
} else {
mapView.setTileSource(TileSourceFactory.DEFAULT_TILE_SOURCE);
}
mapView.setUseDataConnection(false);
mapView.setBuiltInZoomControls(true);
IMapController mapController = mapView.getController();
mapController.setZoom(10);
GeoPoint startPt = new GeoPoint(61.5797,51.5997);
mapController.setCenter(startPt);
mapView.invalidate();
return;
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
MBTilesFileArchive getTileSources always returns empty string, here is implementation:
public Set<String> getTileSources(){
//the MBTiles spec doesn't store source information in it, so we can't return anything
return Collections.EMPTY_SET;
}

In order to make a offline map you should add tiles first. You can use Maperitive app to make your map tiles(zip is easier to manage than sql). Name the zip MapquestOSM. After you have done it create a folder "osmdroid" in phones memory(Directly into the internal memory or sd card) and add your map tiles in it.
Parameters of the XYTileSource changes related to the map tiles you have created. This code handles everything about map tiles itself. I hope it helps you
mapView.setUseDataConnection(false);
mapView.setTileSource(new XYTileSource("MapquestOSM", 2, 15, 256, ".png", new String[]{}));

Related

osmdroid: Tile server which allows bulk download

I am working on an application, for which I need to be able to use map data, while offline. I have looked up how to use the CacheManager and how to download tiles referencing the SampleCacheDownloader.java.
I am using the following code to download the tiles:
CacheManager cMgr = new CacheManager(map);
BoundingBox bBox = cMgr.extendedBoundsFromGeoPoints(currentGeoPoints, 16);
cMgr.downloadAreaAsync(this, bBox, 16, 21, new CacheManager.CacheManagerCallback() {
#Override
public void onTaskComplete() {
}
#Override
public void updateProgress(int progress, int currentZoomLevel, int zoomMin, int zoomMax) {
}
#Override
public void downloadStarted() {
}
#Override
public void setPossibleTilesInArea(int total) {
}
#Override
public void onTaskFailed(int errors) {
}
});
The code works, as in starting the download. But all the tile servers, which are included in the TileSourceFactory class either throw the TileSourcePolicyException "This online tile source doesn't support bulk download" (e.g. MAPNIK and WIKIMEDIA) or fail to get the tiles, because they don't exist for the set zoom levels (e.g. USGS_SAT and USGS_TOPO).
So my question is, are there other publicly available tile servers or do I have to set up my own to be able to download tiles in bulk? Or do I have the completely wrong approach to caching the tiles included in a bounding box with set zoom levels?

Flutter - how to store lists of Strings: (GetStorage or Shared Preferences). using android

So, I have come across a solution for this problem using Get_storage thanks to a couple of great explanations about the topic. I managed to work with getx and the Provider package to save data when adding new stuff and reading it when starting the application (thats the behavior i'm going for here). Said that, i'm having a hard time trying to remove data from memory.
Context
The project is a to-do list app, the front end is working perfectly, but when it comes to storage it gets more complicated. The thing is that i'm very new to flutter and mobile development, i recieved some help but this kind of stuff is still foggy in my brain, i could not remove data using the same logic. When i called box.Remove('key') like the docs say, my ENTIRE list got removed. I don't have a single clue why that happaned.
And so i wonder if i could understand it more by reading through some more explanations, i know Shared Preferences is a great deal do work with this kind of situation, but i would also be confortable with a solution using get_storage since i'm more familiar with it.
the code:\
I'm calling these lists inside a listView on a different file with the help of Provider - -
List<Task> _tasks = [
Task(
name: "Title",
description: "Description",
),
];
Adding tasks to my ListView - -
void add(String newTitle, newDesc) {
final task = Task(name: newTitle, description: newDesc);
_tasks.add(task);
notifyListeners();
}
Here is the removal of a task from the ListView - -
void removeTasks(Task task) {
_tasks.remove(task);
notifyListeners();
}
I tried to implement a logic to write and read data, it worked. But i also tried to use this removeTasks method to remove from storage as well by calling box.Remove('tasks'); ('tasks' was the key passed to the writing and reading methods). It removed everything from memory since my listview got empty.
Since i'm not that experienced, i went through the documentation and could understand some of the SharedPreferences Explanation (same with got_storage) but i'm having a hard time when trying to apply it to my code.
I would appreciate any help using get_storage OR shared preferences to this problem.
Where i'm calling the deletion:
// bool variables that control the state of the screen
// since i can change it to show done tasks or on goind tasks
// dont mind that, i think its irrelevant to the problem.
//
bool isActiveDoing = true;
bool isActiveDone = false;
List finalArray = []; //it will store the tasks
class TaskList extends StatefulWidget {
#override
_TaskListState createState() => _TaskListState();
}
class _TaskListState extends State<TaskList> {
#override
Widget build(BuildContext context) {
//dont mind the if else as well, its not part of the problem
//just using it to handle the state of the screen
if (isActiveDoing) {
finalArray = Provider.of<TasksFunctions>(context).tasks;
}
//TasksFunctions is a class with methods on regards to the storage
//it contains add tasks, remove, etc... i'm using provider to
//link those to the screens with the notifyListeners
if (isActiveDone) {
finalArray = Provider.of<TasksFunctions>(context).doneTasks;
}
//now here is where i call the class tha has the deletion method
return Consumer<TasksFunctions>(
builder: (context, tasksFunctions, child) {
return ListView.builder(
//list view tha has all the tasks
itemCount: finalArray.length,
itemBuilder: (context, index) {
final task = finalArray[index];
//using the slidableWidget to wrap the deletion method
return SlidableWidget(
onDismissed: (action) {
if (isActiveDoing) {
Provider.of<TasksFunctions>(context, listen: false)
.removeTask(task);
//so here is where i'm deleting those tasks, calling that method
//listed up on this post
}
if (isActiveDone {
Provider.of<TasksFunctions>(context, listen: false)
.removeDone(task);
}
},
);
},
);
},
);
}
}
So i spent some time translating the code, but i think that it does not match any of flutter's good practices principles.
I also tried calling storageList.remove(task); and then rewriting it with the box.write('tasks', storageList); but nothing was removed from the memory (maybe because i didn't loop through the whole storageLists searching for the right index i guess)
Sounds like your code is based on my answer to your original question about this.
If that's the case, then the key tasks is the key to the entire list of maps, not a single map or Task. So it's behaving as expected when it wipes all of your tasks.
In order to persist any changes, you'd have to remove that particular map (Task) from storageList then overwrite the box again with box.write('tasks', storageList); It will save over the same list of maps and persist any deletions you made.
If you share your code where you're trying to delete the task and whats going on around it I can give you a more specific example.
EDIT: Answering question in comments.
If you wanted to go the UniqueKey route you wouldn't need the index at all. You could do something like this.
class Task {
final String name;
final String description;
final String key; // not an actual Key but will take the String value of a UniqueKey
Task({this.key, this.name, this.description});
}
When you add a new Task it would look like this.
final task = Task(
description: 'test description',
name: 'test name',
key: UniqueKey().toString());
Then you could use a Map of maps instead of a list of maps and use the key for both.
Map storageList = {};
void addAndStoreTask(Task task) {
_tasks.add(task);
final Map storageMap = {}; // temporary map that gets added to storage
storageMap['name'] = task.name;
storageMap['description'] = task.description;
storageMap['key'] = task.key;
storageList[task.key] = storageMap; // adding temp map to storageList
box.write('tasks', storageList); // adding map of maps to storage
}
Then your restore function would look like this:
void restoreTasks() {
storageList = box.read('tasks'); // initializing list from storage
storageList.forEach((key, value) { // value here is each individual map that was stored
final task =
Task(name: value['name'], description: value['description'], key: key);
_tasks.add(task);
});
}
Then when you go to delete, you iterate through the list and find the matching key.

Runnable for myLocationOverlay.runOnFirstFix not called and getMyLocation() is null

I am trying to get the current location and display it on a OSMdroid map inside an Android application. But I get no location and a Runnable that is supposed to be called the first time the location is found is never called.
I have tried different providers, permissions are all enabled and GPS location, too.
private void getCurrentLocation() {
GpsMyLocationProvider provider = new GpsMyLocationProvider(this);
provider.addLocationSource(LocationManager.GPS_PROVIDER);
provider.addLocationSource(LocationManager.NETWORK_PROVIDER);
myLocationOverlay = new MyLocationNewOverlay(provider, mMapView);
myLocationOverlay.enableMyLocation();
myLocationOverlay.setDrawAccuracyEnabled(true);
myLocationOverlay.runOnFirstFix(new Runnable() {
public void run() {
// never reaches this point
Timber.i("runOnFirstFix");
}
});
mMapView.getOverlays().add(myLocationOverlay);
if (myLocationOverlay.getMyLocation() == null) {
// this shows up
Timber.i("Location not retrieved");
}
}
I understand that the location might not be found as soon as the overlay is added, but I don't understand why the Runnable doesn't work

Windows phone 8 on emulator - why can't I play audio files?

I'm converting an app that was written in Silverlight, and so far I've succeeded in solving all of the problems, except for one:
For some reason, the emulator refuses to play any audio files of the app, and it doesn't even throw an exception. I've checked, and in the ringtone category it can make sounds.
The original code was :
<Grid x:Name="sharedFullScreenFilePathContainer"
Tag="{Binding StringFormat=\{0\},Converter={StaticResource fullScreenImageConverter}}">
<Image x:Name="fullScreenImage" Stretch="Fill"
Source="{Binding ElementName=sharedFullScreenFilePathContainer,Path=Tag, StringFormat=../Assets/images/\{0\}.jpg}"
ImageFailed="onFullScreenImageFailedToLoad" MouseLeftButtonDown="onPressedOnFullScreenImage" />
<MediaElement x:Name="mediaPlayer" AutoPlay="True"
Source="{Binding ElementName=sharedFullScreenFilePathContainer,Path=Tag, StringFormat=../Assets/sounds/\{0\}.wma}" />
</Grid>
so, the image that I set to this item's context is really shown, but the sound that really exists on the path I set to it doesn't play (I've checked in the "Bin" folder).
I've tried to use code instead of xaml, but I still have the same problem.
I've tried this (though it's usually used for background music):
AudioTrack audioTrack = new AudioTrack(new Uri("../Assets/sounds/" + fileToOpen, UriKind.Relative), "", "", "", null);
BackgroundAudioPlayer player = BackgroundAudioPlayer.Instance;
player.Track = audioTrack;
player.Play();
It didn't play anything, and also didn't throw any exception.
I've also tried the next code, but it throws an exception (file not found exception) probably because I don't call it right:
Stream stream = TitleContainer.OpenStream("#Assets/sounds/" + fileToOpen);
SoundEffect effect = SoundEffect.FromStream(stream);
FrameworkDispatcher.Update();
effect.Play();
I've also tried using wma files but it also didn't work.
I also tried to play with the "copy to output directory" parameter of the mp3 files (to "always" and "only if new" ) and with the "build action" parameter (to "none" and "content" ). Nothing helps.
Can anyone please help me? I didn't develop for Silverlight/WP for a very long time and I can't find out how to fix it .
Btw, since later I need to know when the sound has finished playing (and also to be able to stop it), I would like to use code anyway. I would be happy if you could also tell me how to do it too (I can ask it on a new post if needed).
EDIT:
ok , i've found out the problem : i kept getting a weird exception when using the MediaPlayer.Play() method , and after checking out about the exception , i've found out that it's a known issue , and that i need to call FrameworkDispatcher.Update(); right before i call the Play() method .
so the solution would be to do something like this:
Song song = Song.FromUri(...);
MediaPlayer.Stop();
FrameworkDispatcher.Update();
MediaPlayer.Play(song);
the exception is:
'System.InvalidOperationException' occurred in System.Windows.ni.dll"
i've found the solution here .
Now the question is why , and how come I didn't find anything related to it in the demos of windows phone ? Also , i would like to know what this function does .
ok , since nobody gave me an answer to both questions , and I still wish to give the bounty , I will ask another question :
If there is really no solution other than using the MediaPlayer class for windows phone , how do i capture the event of finishing playing an audio file ? Even getting the audio file duration doesn't work (keeps returning 0 length , no matter which class i've tried to use) ...
The BackgroundAudioPlayer can play files only from isolated storage or from a remote URI, that is why you can here anything!
If you have your file as resources in your app, you must first copy them to the isolated store, and then make a reference to the file in the isolated store to your BackgroundAudioPlayer.
private void CopyToIsolatedStorage()
{
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
string[] files = new string[]
{ "Kalimba.mp3",
"Maid with the Flaxen Hair.mp3",
"Sleep Away.mp3" };
foreach (var _fileName in files)
{
if (!storage.FileExists(_fileName))
{
string _filePath = "Audio/" + _fileName;
StreamResourceInfo resource = Application.GetResourceStream(new Uri(_filePath, UriKind.Relative));
using (IsolatedStorageFileStream file = storage.CreateFile(_fileName))
{
int chunkSize = 4096;
byte[] bytes = new byte[chunkSize];
int byteCount;
while ((byteCount = resource.Stream.Read(bytes, 0, chunkSize)) > 0)
{
file.Write(bytes, 0, byteCount);
}
}
}
}
}
}
And then you can make a list of your songs
private static List<AudioTrack> _playList = new List<AudioTrack>
{
new AudioTrack(new Uri("Kalimba.mp3", UriKind.Relative),
"Kalimba",
"Mr. Scruff",
"Ninja Tuna",
null),
new AudioTrack(new Uri("Maid with the Flaxen Hair.mp3", UriKind.Relative),
"Maid with the Flaxen Hair",
"Richard Stoltzman",
"Fine Music, Vol. 1",
null),
new AudioTrack(new Uri("Sleep Away.mp3", UriKind.Relative),
"Sleep Away",
"Bob Acri",
"Bob Acri",
null),
// A remote URI
new AudioTrack(new Uri("http://traffic.libsyn.com/wpradio/WPRadio_29.mp3", UriKind.Absolute),
"Episode 29",
"Windows Phone Radio",
"Windows Phone Radio Podcast",
null)
};
And play your tracks!
private void PlayNextTrack(BackgroundAudioPlayer player)
{
if (++currentTrackNumber >= _playList.Count)
{
currentTrackNumber = 0;
}
PlayTrack(player);
}
private void PlayPreviousTrack(BackgroundAudioPlayer player)
{
if (--currentTrackNumber < 0)
{
currentTrackNumber = _playList.Count - 1;
}
PlayTrack(player);
}
private void PlayTrack(BackgroundAudioPlayer player)
{
// Sets the track to play. When the TrackReady state is received,
// playback begins from the OnPlayStateChanged handler.
player.Track = _playList[currentTrackNumber];
}
If you want the MediaElement to work from your code you can do something like this!
MediaElement me = new MediaElement();
// Must add the MediaElement to some UI container on
// your page or some UI-control, otherwise it will not play!
this.LayoutRoot.Children.Add(me);
me.Source = new Uri("Assets/AwesomeMusic.mp3", UriKind.RelativeOrAbsolute);
me.Play();
Use the MediaElement instead, this can play media files stored in your application, but stops playing when the application stops (you can make some advance chance to your app so it keep running, but it will not work very well)
In your XAML:
<Button x:Name="PlayFile"
Click="PlayFile_Click_1"
Content="Play mp3" />
In your Code behind:
MediaElement MyMedia = new MediaElement();
// Constructor
public MainPage()
{
InitializeComponent();
this.LayoutRoot.Children.Add(MyMedia);
MyMedia.CurrentStateChanged += MyMedia_CurrentStateChanged;
MyMedia.MediaEnded += MyMedia_MediaEnded;
}
void MyMedia_MediaEnded(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Ended event " + MyMedia.CurrentState.ToString());
// Set the source to null, force a Close event in current state
MyMedia.Source = null;
}
void MyMedia_CurrentStateChanged(object sender, RoutedEventArgs e)
{
switch (MyMedia.CurrentState)
{
case System.Windows.Media.MediaElementState.AcquiringLicense:
break;
case System.Windows.Media.MediaElementState.Buffering:
break;
case System.Windows.Media.MediaElementState.Closed:
break;
case System.Windows.Media.MediaElementState.Individualizing:
break;
case System.Windows.Media.MediaElementState.Opening:
break;
case System.Windows.Media.MediaElementState.Paused:
break;
case System.Windows.Media.MediaElementState.Playing:
break;
case System.Windows.Media.MediaElementState.Stopped:
break;
default:
break;
}
System.Diagnostics.Debug.WriteLine("CurrentState event " + MyMedia.CurrentState.ToString());
}
private void PlayFile_Click_1(object sender, RoutedEventArgs e)
{
// Play Awesome music file, stored as content in the Assets folder in your app
MyMedia.Source = new Uri("Assets/AwesomeMusic.mp3", UriKind.RelativeOrAbsolute);
MyMedia.Play();
}
Audio track plays audio files stored in isolated storage or streamed over the internet.
Playing audio files stored within the application package works fine for me. I got files named like "Alarm01.wma" in project folder Resources\Alarms. I then play these sounds like this:
using Microsoft.Xna.Framework.Media;
...
Song s = Song.FromUri("alarm", new Uri(#"Resources/Alarms/Alarm01.wma", UriKind.Relative));
MediaPlayer.Play(s);
Also don't forget to reference Microsoft.Xna.Framework library.
I guess it should work fine for mp3 files and files stored in IsolatedStorage as well.

Create and save multiple list of text into Isolated Storage

How do I create more than one list of text data and save it into the isolated storage?
I need to retrieve and display different saved list as well.
I am doing an application like a drink list where user can create multiple drink list containing many different kinds of drink.
I can only create and save one list of drink text at the moment. If I were to add more drink text inside the list again and save it, the list will be overwritten by the latest different drink text.
// Save List of drink text
private void addListBtn_Click(object sender, RoutedEventArgs e)
{
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();
storage.CreateDirectory("ListFolder");
StreamWriter writeFile = new StreamWriter(new IsolatedStorageFileStream("ListFolder\\savedList.txt", FileMode.OpenOrCreate, storage));
for (int i = 0; i < (Application.Current as App).userDrinksList.Count; i++)
{
String drink = (Application.Current as App).userDrinksList[i].ToString();
writeFile.WriteLine(drink.ToString());
}
writeFile.Close();
MessageBox.Show("List added into favourite list.");
}
// Display saved lists
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();
StreamReader readFile = null;
{
readFile = new StreamReader(new IsolatedStorageFileStream("ListFolder\\savedList.txt", FileMode.Open, storage));
listNumberListBox.Items.Add(readFile.ReadToEnd());
readFile.Close();
}
}
You are saving it as savedList.txt. You need to save each list as a separate file. eg list1.txt, list2.txt etc.
Perhaps you also need a list of lists so you know which file = which list.
Your addListBtn_Click method is assuming it can find the list of drinks in a userDrinksList member of your Application instance, however your PhoneApplicationPage_Loaded method doesn't populate that member.
In your PhoneApplicationPage_Loaded method you could do:
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
using(var stream = storage.OpenFile("ListFolder\\savedList.txt", FileMode.Open))
using(StreamReader readFile = new StreamReader(stream))
{
for (string line = readFile.ReadLine(); line != null; line = readFile.ReadLine())
{
listNumberListBox.Items.Add(line);
((App) Application.Current).userDrinksList.Add(line)
}
}
The 'usings' ensure that the resources are properly closed/disposed, so you don't need to explicitly close. You were reading in the complete contents - you need to read it in line by line.