├── .gitignore ├── .idea ├── assetWizardSettings.xml ├── caches │ ├── deviceStreaming.xml │ └── gradle_models.ser ├── codeStyles │ └── Project.xml ├── compiler.xml ├── deploymentTargetSelector.xml ├── dictionaries │ └── bojko108.xml ├── gradle.xml ├── migrations.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── .project ├── .settings └── org.eclipse.buildship.core.prefs ├── HOMEPAGE.md ├── LICENSE ├── README.md ├── app ├── .classpath ├── .gitignore ├── .project ├── .settings │ └── org.eclipse.buildship.core.prefs ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ ├── java │ │ └── com │ │ │ └── bojko108 │ │ │ └── mobiletileserver │ │ │ └── ExampleInstrumentedTest.java │ └── test │ │ └── java │ │ └── com │ │ └── bojko108 │ │ └── mobiletileserver │ │ └── ExampleUnitTest.java │ └── main │ ├── AndroidManifest.xml │ ├── ic_launcher-web.png │ ├── java │ └── com │ │ └── bojko108 │ │ └── mobiletileserver │ │ ├── InfoActivity.java │ │ ├── MainActivity.java │ │ ├── SettingsActivity.java │ │ ├── ShortcutsActivity.java │ │ ├── server │ │ ├── ServerFiles.java │ │ ├── TileServer.java │ │ ├── TileService.java │ │ ├── TileServiceReceiver.java │ │ └── tilesets │ │ │ ├── MBTilesDatabase.java │ │ │ ├── StaticFileInfo.java │ │ │ └── TilesetInfo.java │ │ └── utils │ │ ├── BatteryOptimization.java │ │ ├── HelperClass.java │ │ └── TileGrid.java │ └── res │ ├── drawable-anydpi │ └── ic_not_stop.xml │ ├── drawable-hdpi │ └── ic_stat_name.png │ ├── drawable-mdpi │ └── ic_stat_name.png │ ├── drawable-xhdpi │ └── ic_stat_name.png │ ├── drawable-xxhdpi │ └── ic_stat_name.png │ ├── drawable │ ├── ic_help_24dp.xml │ ├── ic_info_black_24dp.xml │ ├── ic_notifications_black_24dp.xml │ ├── ic_settings_24dp.xml │ ├── ic_start_24dp.xml │ ├── ic_stop_24dp.xml │ ├── ic_sync_black_24dp.xml │ ├── icon_info.png │ ├── img_tiles.png │ ├── shortcut_browse_icon.png │ ├── shortcut_navigate_icon.png │ ├── shortcut_start_icon.png │ └── shortcut_stop_icon.png │ ├── layout │ ├── activity_info.xml │ ├── activity_main.xml │ └── activity_settings.xml │ ├── menu │ └── main_menu.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── raw │ ├── badrequest.html │ ├── home.html │ ├── internalservererror.html │ ├── mbtilesserviceinfo.txt │ ├── no_tile.png │ ├── oruxmaps.txt │ ├── preview.html │ ├── services.html │ ├── staticfileinfo.txt │ ├── staticfiles.html │ └── tileserviceinfo.txt │ ├── values-bg-rBG │ └── strings.xml │ ├── values-bg │ └── strings.xml │ ├── values │ ├── colors.xml │ ├── dimens.xml │ ├── ic_launcher_background.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ ├── preferences.xml │ └── shortcuts.xml ├── build.gradle ├── docs ├── 01.jpg ├── 02.jpg ├── 03.jpg ├── 04.jpg ├── 05.jpg ├── 06.jpg ├── 07.jpg ├── README.md ├── feature-graphic.jpg ├── icon.cdr ├── icon.png └── no_tile.png ├── fastlane └── metadata │ └── android │ ├── de │ └── short_description.txt │ └── en-US │ ├── full_description.txt │ ├── images │ ├── featureGraphic.jpg │ ├── icon.png │ └── phoneScreenshots │ │ ├── 01.jpg │ │ ├── 02.jpg │ │ ├── 03.jpg │ │ ├── 04.jpg │ │ ├── 05.jpg │ │ ├── 06.jpg │ │ └── 07.jpg │ └── short_description.txt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | app/release 9 | app/debug 10 | /captures 11 | .externalNativeBuild 12 | SIGN_APK.md -------------------------------------------------------------------------------- /.idea/assetWizardSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 230 | 231 | -------------------------------------------------------------------------------- /.idea/caches/gradle_models.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/.idea/caches/gradle_models.ser -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | xmlns:android 14 | 15 | ^$ 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | xmlns:.* 25 | 26 | ^$ 27 | 28 | 29 | BY_NAME 30 | 31 |
32 |
33 | 34 | 35 | 36 | .*:id 37 | 38 | http://schemas.android.com/apk/res/android 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | .*:name 48 | 49 | http://schemas.android.com/apk/res/android 50 | 51 | 52 | 53 |
54 |
55 | 56 | 57 | 58 | name 59 | 60 | ^$ 61 | 62 | 63 | 64 |
65 |
66 | 67 | 68 | 69 | style 70 | 71 | ^$ 72 | 73 | 74 | 75 |
76 |
77 | 78 | 79 | 80 | .* 81 | 82 | ^$ 83 | 84 | 85 | BY_NAME 86 | 87 |
88 |
89 | 90 | 91 | 92 | .* 93 | 94 | http://schemas.android.com/apk/res/android 95 | 96 | 97 | ANDROID_ATTRIBUTE_ORDER 98 | 99 |
100 |
101 | 102 | 103 | 104 | .* 105 | 106 | .* 107 | 108 | 109 | BY_NAME 110 | 111 |
112 |
113 |
114 |
115 |
116 |
-------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/deploymentTargetSelector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/dictionaries/bojko108.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | availabletilesets 5 | baselayer 6 | basemap 7 | bojko 8 | imagepng 9 | mbtiles 10 | orux 11 | oruxmaps 12 | quadkey 13 | rootpath 14 | serverport 15 | staticfile 16 | tilesets 17 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 27 | 47 | 48 | 49 | 50 | 51 | 52 | 54 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Mobile Tile Server 4 | Project Mobile Tile Server created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | 19 | 1666348711557 20 | 21 | 30 22 | 23 | org.eclipse.core.resources.regexFilterMatcher 24 | node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | arguments=--init-script C\:\\Users\\bojko108\\AppData\\Roaming\\Code\\User\\globalStorage\\redhat.java\\1.33.0\\config_win\\org.eclipse.osgi\\55\\0\\.cp\\gradle\\init\\init.gradle --init-script C\:\\Users\\bojko108\\AppData\\Roaming\\Code\\User\\globalStorage\\redhat.java\\1.33.0\\config_win\\org.eclipse.osgi\\55\\0\\.cp\\gradle\\protobuf\\init.gradle 2 | auto.sync=false 3 | build.scans.enabled=false 4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) 5 | connection.project.dir= 6 | eclipse.preferences.version=1 7 | gradle.user.home= 8 | java.home=C\:/Program Files/Java/jdk1.8.0_181 9 | jvm.arguments= 10 | offline.mode=false 11 | override.workspace.settings=true 12 | show.console.view=true 13 | show.executions.view=true 14 | -------------------------------------------------------------------------------- /HOMEPAGE.md: -------------------------------------------------------------------------------- 1 | # Mobile Tile Server 2 | 3 | Mobile Tile Server is a local HTTP server, serving Map Tiles from the device storage. When the server is running you can access the map tiles from different mapping applications. The application provides access to two types of tilesets: 4 | 5 | - Map Tiles stored in directories - [Slippy Maps](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames) 6 | - Map Tiles stored in MBTiles files - [MBTiles files](https://github.com/mapbox/mbtiles-spec) 7 | 8 | # Available HTTP routes 9 | 10 | ### [Get a list of all MBTiles Tilesets](/mbtiles) 11 | 12 | ### [Get a list of all Directory Tilesets](/tiles) 13 | 14 | ### [Get a list of all Tilesets in JSON format](/availabletilesets) 15 | 16 | ### [Get a list of all static files](/static) 17 | 18 | # Info 19 | 20 | The map tiles must be stored in device storage and the app should have access to the raw files. In app settings you can change the root directory, where the tilesets are stored and also the server's listening port. When the server is running all tilesets from the root directory can be accessed using HTTP GET Requests. 21 | 22 | --- 23 | 24 | > ⚠️ The tile server is running in background and battery optimization functions in Android can cause it to become inactive after time. In order to be able to use it for a longer periods of time it is recommended to enable manual settings for **Mobile Tile Server** App in Device Settings > Battery > App Launch. 25 | 26 | ## Default no-tile image 27 | 28 | Default no-tile image (image served when a map tile is not available) can be changed by puting a `no_tile.png` file in your root directory: 29 | 30 | ``` 31 | 📦MobileTileServer --> server root directory 32 | ┣ 📂tiles 33 | ┣ 📂mbtiles 34 | ┗ 📜no_tile.png --> default no-tile image to be used 35 | ``` 36 | 37 | ## Directory Tilesets 38 | 39 | Directory Tilesets are image files stored in directories. Each zoom level (`z` coordinate) is stored in a separate subdirectory and each tile column (`x` coordinate) is stored in additional subdirectory. This is an example file structure of the root directory: 40 | 41 | ``` 42 | 📦MobileTileServer --> server root directory 43 | ┣ 📂tiles 44 | ┃ ┣ 📂default --> tileset name 45 | ┃ ┃ ┣ 📂1 --> zoom level (z coordinate) 46 | ┃ ┃ ┃ ┗ 📂1 --> x coordinate 47 | ┃ ┃ ┃ ┃ ┗ 📜0.png --> map tile (y coordinate) 48 | ┃ ┃ ┣ 📂2 49 | ┃ ┃ ┃ ┗ 📂2 50 | ┃ ┃ ┃ ┃ ┗ 📜1.png 51 | ┃ ┃ ┃ ┗ ... 52 | ┃ ┃ ┗ ... 53 | ┃ ┗ ... 54 | ┗ 📂mbtiles 55 | ``` 56 | 57 | ## MBTiles Tilesets 58 | 59 | MBTiles Tilesets are SQLite databases with known schema - [MBTiles](https://github.com/mapbox/mbtiles-spec). This is an example file structure of the root directory: 60 | 61 | ``` 62 | 63 | 📦MobileTileServer --> server root directory 64 | ┣ 📂mbtiles 65 | ┃ ┣ 📜glavatar-kaleto-M5000-zoom1_17.mbtiles --> MBTiles Tileset 66 | ┃ ┣ 📜glavatar-kaleto-orthophoto-zoom1_18.mbtiles --> MBTiles Tileset 67 | ┃ ┗ ... 68 | ┗ 📂tiles 69 | 70 | ``` 71 | 72 | ## Static files 73 | 74 | Returns a list of all static files served by this server. This is an example file structure of the root directory: 75 | 76 | ``` 77 | 78 | 📦MobileTileServer --> server root directory 79 | ┣ 📂static 80 | ┃ ┣ 📜cez.json --> static file 81 | ┃ ┣ 📜test.dwg --> another static file 82 | ┃ ┗ ... 83 | ┗ 📂tiles 84 | 85 | ``` 86 | 87 | ## How to use in mapping applications 88 | 89 | ### Mobile Geodesy App 90 | 91 | [Mobile Geodesy](https://github.com/bojko108/mobile-geodesy) is a mapping application, which can be used for collecting data and navigation. The application is capable of displaying tilesets, served from this tile server. At runtime, the Mobile Geodesy App will connect to `http://localhost:{port}/availabletilesets` and will download the list of all available tilesets. Then in the map activity, you can select the desired tileset to load as a basemap. 92 | 93 | ### OruxMaps App 94 | 95 | [OruxMaps](https://www.oruxmaps.com/cs/en/) is another mapping application with lots of tools and capabilities. The app is also capable of loading tilesets by adding the needed infromation in app's configuration file, stored in `/storage/emulated/0/oruxmaps/mapfiles/onlinemapsources.xml`. There you can add additional map sources, which can be then used in the application as basemaps. This is an example: 96 | 97 | 1. Open the configuration file, stored in `/storage/emulated/0/oruxmaps/mapfiles/onlinemapsources.xml`. 98 | 2. Add this XML to the file: 99 | 100 | ```xml 101 | 102 | glavatar-kaleto-orthophoto-zoom1_18 103 | 104 | 1 105 | 18 106 | MERCATORESFERICA 107 | 0 108 | 1 109 | 0 110 | 0 111 | 112 | ``` 113 | 114 | 3. Do not forget to set the correct uid value in the xml! 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mobile Tile Server 2 | 3 | | IzzyOnDroid F-Droid | Play Store | 4 | |:-------------------:|:-------------------:| 5 | | F-Droid | Get it on Google Play | 6 | 7 | Mobile Tile Server is a local HTTP server, serving Map Tiles from the device storage. When the server is running you can access the map tiles from different mapping applications. The application provides access to two types of tilesets: 8 | 9 | - Map Tiles stored in directories - [Slippy Maps](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames) 10 | - Map Tiles stored in MBTiles files - [MBTiles files](https://github.com/mapbox/mbtiles-spec) 11 | 12 | Simmilar map tiles server is available for Windows (with NodeJS) - [Windows Tile Server](https://github.com/bojko108/windows-tile-server). 13 | 14 | ## Contents 15 | 16 | - [Info](#info) 17 | - [Available HTTP routes](#available-http-routes) 18 | - [Directory Tilesets](#directory-tilesets) 19 | - [Get a list of available Directory Tilesets](#get-a-list-of-available-directory-tilesets) 20 | - [MBTiles Tilesets](#mbtiles-tilesets) 21 | - [Get a list of available MBTiles Tilesets](#get-a-list-of-available-mbtiles-tilesets) 22 | - [Preview Tilesets](#preview-tilesets) 23 | - [Examples](#examples) 24 | - [Mobile Geodesy App](#mobile-geodesy-app) 25 | - [OruxMaps App](#oruxmaps-app) 26 | - [Dependencies](#dependencies) 27 | 28 | ## Info 29 | 30 | The map tiles must be stored in device storage and the app should have access to the raw files. In app settings you can change the root directory, where the tilesets are stored and also the server's listening port. When the server is running all tilesets from the root directory can be accessed using HTTP GET Requests. 31 | 32 | --- 33 | 34 | > ⚠️ The tile server is running in background and battery optimization functions in Android can cause it to become inactive after time. In order to be able to use it for a longer periods of time it is recommended to enable manual settings for **Mobile Tile Server** App in Device Settings > Battery > App Launch. 35 | 36 | ### Available HTTP routes 37 | 38 | - `http://localhost:{port}/` - this is the home address of the server where you can get usefull infromation on how to use the tilesets in your mapping applications 39 | - `http://localhost:{port}/preview/mbtiles?tileset={tileset}` - preview a MBTiles tileset, where `tileset` query parameter sets the name of the MBTiles file 40 | - `http://localhost:{port}/preview/tiles?tileset={tileset}` - preview a Directory tileset, where `tileset` query parameter sets the name of the directory 41 | - `http://localhost:{port}/mbtiles` - list all available MBTiles tilesets, served by the server 42 | - `http://localhost:{port}/mbtiles?tileset={tileset}&z={z}&x={x}&y={y}` - returns a map tile from a MBTiles tileset, where `tileset` query parameter sets the name of the MBTiles file; `z`, `x` and `y` represents [tile coordinates](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames) - if your mapping application uses [TMS Schema](https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md#content-1) use nagative values for `y`. 43 | - `http://localhost:{port}/tiles` - list all available Directory tilesets, served by the server 44 | - `http://localhost:{port}/tiles/{tileset}/{z}/{x}/{y}.png` - returns a map tile from a Directory tileset, where `tileset` query parameters sets the name of the directory; `z`, `x` and `y` represents [tile coordinates](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames). 45 | - `http://localhost:{port}/availabletilesets` - returns all available tilesets in JSON format - check the example use with [Mobile Geodesy App](#mobile-geodesy-app) for more details. 46 | - `http://localhost:{port}/static` - returns all available static files for download 47 | - `http://localhost:{port}/static?filename={file_name}` - gets the specified static file 48 | 49 | ## Default no-tile image 50 | 51 | Default no-tile image (image served when a map tile is not available) can be changed by puting a `no_tile.png` file in your root directory: 52 | 53 | ``` 54 | 📦MobileTileServer --> server root directory 55 | ┣ 📂tiles 56 | ┣ 📂mbtiles 57 | ┗ 📜no_tile.png --> default no-tile image to be used 58 | ``` 59 | 60 | ## Directory Tilesets 61 | 62 | Directory Tilesets are image files stored in directories. Each zoom level (`z` coordinate) is stored in a separate subdirectory and each tile column (`x` coordinate) is stored in additional subdirectory. This is an example file structure of the root directory: 63 | 64 | ``` 65 | 📦MobileTileServer --> server root directory 66 | ┣ 📂tiles 67 | ┃ ┣ 📂default --> tileset name 68 | ┃ ┃ ┣ 📂1 --> zoom level (z coordinate) 69 | ┃ ┃ ┃ ┗ 📂1 --> x coordinate 70 | ┃ ┃ ┃ ┃ ┗ 📜0.png --> map tile (y coordinate) 71 | ┃ ┃ ┣ 📂2 72 | ┃ ┃ ┃ ┗ 📂2 73 | ┃ ┃ ┃ ┃ ┗ 📜1.png 74 | ┃ ┃ ┃ ┗ ... 75 | ┃ ┃ ┗ ... 76 | ┃ ┗ ... 77 | ┗ 📂mbtiles 78 | ``` 79 | 80 | #### Access 81 | 82 | Add the following url to your mapping application: 83 | 84 | ``` 85 | http://localhost:{port}/tiles/{tileset}/{z}/{x}/{y}.png 86 | ``` 87 | 88 | - `tileset` - represents the name of the directory 89 | - `z` - represents the zoom level 90 | - `x` - represents tile column 91 | - `y` - represents tile row - if your mapping application uses TMS schema - set this value as negative 92 | 93 | You can go to the [examples](#examples) for more details on how to use the tilesets. 94 | 95 | ### Get a list of available Directory Tilesets 96 | 97 | You can list all available Directory Tilesets by going to: 98 | 99 | ``` 100 | http://localhost:{port}/tiles 101 | ``` 102 | 103 | This will return a list of all available Directory Tilesets, served from this server as well as additional information, describing the parameters of the tilesets: 104 | 105 | ### Example Repsonse 106 | 107 | > **Available Directory Tilesets** 108 | > 109 | > This is a list of all directories, containing tiles and are served from this service: 110 | > 111 | > - **default** - preview with Leaflet viewer 112 | > 113 | > | Property | Value | 114 | > | ------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | 115 | > | Min Zoom | 1 | 116 | > | Max Zoom | 12 | 117 | > | Bounds | 22.0,40.5,28.0,45.0 (unable to calculate, default value is returned) | 118 | > | Center | 25.0,42.75,6.0 (unable to calculate, default value is returned) | 119 | > | For use in Mobile Geodesy | Tilesets are automatically added to Mobile Geodesy App. Just start the tile server, open Mobile Geodesy and choose desired tileset to load it as a basemap. | 120 | > | For use in OruxMaps | XML text to be added to OruxMaps App configuration file stored in: _/storage/emulated/0/oruxmaps/mapfiles/onlinemapsources.xml_ | 121 | 122 | ## MBTiles Tilesets 123 | 124 | MBTiles Tilesets are SQLite databases with known schema - [MBTiles](https://github.com/mapbox/mbtiles-spec). This is an example file structure of the root directory: 125 | 126 | ``` 127 | 128 | 📦MobileTileServer --> server root directory 129 | ┣ 📂mbtiles 130 | ┃ ┣ 📜glavatar-kaleto-M5000-zoom1_17.mbtiles --> MBTiles Tileset 131 | ┃ ┣ 📜glavatar-kaleto-orthophoto-zoom1_18.mbtiles --> MBTiles Tileset 132 | ┃ ┗ ... 133 | ┗ 📂tiles 134 | 135 | ``` 136 | 137 | #### Access 138 | 139 | Add the following url to your mapping application: 140 | 141 | ``` 142 | 143 | `http://localhost:{port}/mbtiles?tileset={tileset}&z={z}&x={x}&y={y} 144 | 145 | ``` 146 | 147 | - `tileset` - represents the name of the directory 148 | - `z` - represents the zoom level 149 | - `x` - represents tile column 150 | - `y` - represents tile row - if your mapping application uses TMS schema - set this value as negative 151 | 152 | You can go to the [examples](#examples) for more details on how to use the tilesets. 153 | 154 | ### Get a list of available MBTiles Tilesets 155 | 156 | You can list all available MBTIles Tilesets by going to: 157 | 158 | ``` 159 | http://localhost:{port}/mbtiles 160 | ``` 161 | 162 | This will return a list of all available MBTiles Tilesets, served from this server as well as additional information, describing the parameters of the tilesets: 163 | 164 | ### Example Repsonse 165 | 166 | > **Available MBTiles Tilesets** 167 | > 168 | > This is a list of all MBTiles tilesets, served from this server: 169 | > 170 | > - **glavatar-kaleto-M5000-zoom1_17.mbtiles** - preview with Leaflet viewer 171 | > 172 | > | Property | Value | 173 | > | ------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | 174 | > | Name | glavatar-kaleto-1-17 | 175 | > | Version | 1.1 | 176 | > | Description | Glavatar - Kaleto, ETK, Scale 1:5000 | 177 | > | Min Zoom | 1 | 178 | > | Max Zoom | 17 | 179 | > | Bounds | 24.762587288428623,42.29438246738081,25.033514158464705,42.50673679522477 | 180 | > | Center | 24.898050723446666,42.400559631302784,10.0 | 181 | > | For use in Mobile Geodesy | Tilesets are automatically added to Mobile Geodesy App. Just start the tile server, open Mobile Geodesy and choose desired tileset to load it as a basemap. | 182 | > | For use in OruxMaps | XML text to be added to OruxMaps App configuration file stored in: _/storage/emulated/0/oruxmaps/mapfiles/onlinemapsources.xml_ | 183 | 184 | ## Static files 185 | 186 | Returns a list of all static files served by this server. This is an example file structure of the root directory: 187 | 188 | ``` 189 | 190 | 📦MobileTileServer --> server root directory 191 | ┣ 📂static 192 | ┃ ┣ 📜cez.json --> static file 193 | ┃ ┣ 📜test.dwg --> another static file 194 | ┃ ┗ ... 195 | ┗ 📂tiles 196 | 197 | ``` 198 | 199 | ### Get a list of all available static files 200 | 201 | You can list all available static files by going to: 202 | 203 | ``` 204 | http://localhost:{port}/static 205 | ``` 206 | 207 | This will return a list of all available static files, served from this server as well as additional information, describing the parameters of the files: 208 | 209 | ### Example Repsonse 210 | 211 | > **Available Static Files** 212 | > 213 | > This is a list of all static files, which are served from this service: 214 | > 215 | > - **cez.json** - download file 216 | > 217 | > | Property | Value | 218 | > | ------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | 219 | > | Content Type | application/json | 220 | > | Size | 6 KB 221 | 222 | ## Preview Tilesets 223 | 224 | All available tilesets can be previewed in a simple Map Viewer created with [Leaflet](https://leafletjs.com). Each type of tileset is accessible on different address: 225 | 226 | ### Directory Tilesets 227 | 228 | Navigate to: 229 | 230 | ``` 231 | http://localhost:{port}/preview/tiles?tileset={tileset} 232 | ``` 233 | 234 | where `tileset` is the name of the directory containing the map tiles. 235 | 236 | ### MBTiles Tilesets 237 | 238 | Navigate to: 239 | 240 | ``` 241 | http://localhost:{port}/preview/mbtiles?tileset={tileset} 242 | ``` 243 | 244 | where `tileset` is the name of the MBTiles file containing the map tiles. 245 | 246 | ## Static files 247 | 248 | Navigate to: 249 | 250 | ``` 251 | http://localhost:{port}/static?filename={file_name} 252 | ``` 253 | 254 | where `file_name` is the name of the static file to return. 255 | 256 | ## Examples 257 | 258 | ### Mobile Geodesy App 259 | 260 | [Mobile Geodesy](https://github.com/bojko108/mobile-geodesy) is a mapping application, which can be used for collecting data and navigation. The application is capable of displaying tilesets, served from this tile server. At runtime, the Mobile Geodesy App will connect to `http://localhost:{port}/availabletilesets` and will download the list of all available tilesets. Then in the map activity, you can select the desired tileset to load as a basemap. 261 | 262 | ### OruxMaps App 263 | 264 | [OruxMaps](https://www.oruxmaps.com/cs/en/) is another mapping application with lots of tools and capabilities. The app is also capable of loading tilesets by adding the needed infromation in app's configuration file, stored in `/storage/emulated/0/oruxmaps/mapfiles/onlinemapsources.xml`. There you can add additional map sources, which can be then used in the application as basemaps. This is an example: 265 | 266 | 1. Open the configuration file, stored in `/storage/emulated/0/oruxmaps/mapfiles/onlinemapsources.xml`. 267 | 2. Add this XML to the file: 268 | 269 | ```xml 270 | 271 | glavatar-kaleto-orthophoto-zoom1_18 272 | 273 | 1 274 | 18 275 | MERCATORESFERICA 276 | 0 277 | 1 278 | 0 279 | 0 280 | 281 | ``` 282 | 283 | 3. Do not forget to set the correct uid value in the xml! 284 | 285 | ## Dependecies 286 | 287 | The HTTP server is build using [AndroidAsync](https://github.com/koush/AndroidAsync) library. 288 | 289 | ``` 290 | 291 | dependencies { 292 | implementation 'com.koushikdutta.async:androidasync:3.0.8' 293 | } 294 | 295 | ``` 296 | -------------------------------------------------------------------------------- /app/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | app 4 | Project app created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | 25 | 1666348711495 26 | 27 | 30 28 | 29 | org.eclipse.core.resources.regexFilterMatcher 30 | node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir=.. 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileOptions { 5 | sourceCompatibility JavaVersion.VERSION_11 6 | targetCompatibility JavaVersion.VERSION_11 7 | } 8 | compileSdkVersion 34 9 | defaultConfig { 10 | applicationId "com.bojko108.mobiletileserver" 11 | minSdkVersion 26 12 | targetSdkVersion 34 13 | versionCode 11 14 | versionName "5.4" 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | vectorDrawables.useSupportLibrary = true 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled true 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | debug { 24 | minifyEnabled false 25 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 26 | } 27 | applicationVariants.all { variant -> 28 | variant.outputs.all { 29 | if (variant.buildType.name == "debug") { 30 | outputFileName = "MobileTileServer-v${variant.versionName}.${variant.versionCode}-debug.apk" 31 | } else { 32 | outputFileName = "MobileTileServer-v${variant.versionName}.${variant.versionCode}.apk" 33 | } 34 | } 35 | } 36 | } 37 | namespace 'com.bojko108.mobiletileserver' 38 | dependenciesInfo { 39 | // Disables dependency metadata when building APKs (for IzzyOnDroid/F-Droid) 40 | includeInApk = false 41 | // Disables dependency metadata when building Android App Bundles (for Google Play) 42 | includeInBundle = false 43 | } 44 | } 45 | 46 | dependencies { 47 | implementation 'com.koushikdutta.async:androidasync:3.0.8' 48 | implementation fileTree(dir: 'libs', include: ['*.jar']) 49 | implementation 'androidx.appcompat:appcompat:1.7.1' 50 | implementation 'androidx.constraintlayout:constraintlayout:2.2.1' 51 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 52 | implementation 'androidx.vectordrawable:vectordrawable:1.2.0' 53 | implementation 'androidx.preference:preference:1.2.1' 54 | implementation 'com.google.android.material:material:1.12.0' 55 | testImplementation 'junit:junit:4.13.2' 56 | androidTestImplementation 'androidx.test.ext:junit:1.2.1' 57 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' 58 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/bojko108/mobiletileserver/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.bojkosoft.bojko108.mobiletileserver; 2 | 3 | import android.content.Context; 4 | import androidx.test.platform.app.InstrumentationRegistry; 5 | import androidx.test.ext.junit.runners.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 23 | 24 | assertEquals("com.bojkosoft.bojko108.mobiletileserver", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/androidTest/test/java/com/bojko108/mobiletileserver/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.bojkosoft.bojko108.mobiletileserver; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 35 | 38 | 41 | 42 | 45 | 48 | 49 | 52 | 53 | 58 | 59 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /app/src/main/java/com/bojko108/mobiletileserver/InfoActivity.java: -------------------------------------------------------------------------------- 1 | package com.bojko108.mobiletileserver; 2 | 3 | import android.os.Bundle; 4 | import android.widget.TextView; 5 | 6 | import com.bojko108.mobiletileserver.BuildConfig; 7 | 8 | import androidx.appcompat.app.AppCompatActivity; 9 | 10 | public class InfoActivity extends AppCompatActivity { 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | setContentView(R.layout.activity_info); 16 | 17 | TextView textView = (TextView) findViewById(R.id.textView); 18 | textView.setText(String.format(textView.getText().toString(), BuildConfig.VERSION_NAME)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/bojko108/mobiletileserver/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.bojko108.mobiletileserver; 2 | 3 | import android.Manifest; 4 | import android.app.Activity; 5 | import android.app.AlertDialog; 6 | import android.content.BroadcastReceiver; 7 | import android.content.Context; 8 | import android.content.DialogInterface; 9 | import android.content.Intent; 10 | import android.content.IntentFilter; 11 | import android.content.SharedPreferences; 12 | import android.content.pm.PackageManager; 13 | import android.net.Uri; 14 | import android.os.Build; 15 | import android.os.Environment; 16 | import android.preference.PreferenceManager; 17 | 18 | import androidx.appcompat.app.AppCompatActivity; 19 | import androidx.core.app.ActivityCompat; 20 | import androidx.localbroadcastmanager.content.LocalBroadcastManager; 21 | 22 | import android.os.Bundle; 23 | import android.provider.Settings; 24 | import android.view.Menu; 25 | import android.view.MenuInflater; 26 | import android.view.MenuItem; 27 | import android.view.View; 28 | import android.widget.ImageView; 29 | import android.widget.Toast; 30 | 31 | import com.bojko108.mobiletileserver.server.TileService; 32 | import com.bojko108.mobiletileserver.server.TileServiceReceiver; 33 | import com.google.android.material.button.MaterialButton; 34 | 35 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 36 | 37 | // used to ping TileService to see if it's running 38 | private LocalBroadcastManager manager; 39 | 40 | // server port and root path: stored in shared preferences 41 | private int serverPort; 42 | private String rootPath; 43 | private boolean running; 44 | 45 | // Storage Permissions 46 | private static final int REQUEST_EXTERNAL_STORAGE = 1; 47 | private static String[] PERMISSIONS_STORAGE = { 48 | Manifest.permission.READ_EXTERNAL_STORAGE, 49 | Manifest.permission.WRITE_EXTERNAL_STORAGE 50 | }; 51 | 52 | @Override 53 | protected void onCreate(Bundle savedInstanceState) { 54 | super.onCreate(savedInstanceState); 55 | setContentView(R.layout.activity_main); 56 | 57 | this.manager = LocalBroadcastManager.getInstance(this); 58 | 59 | findViewById(R.id.buttonStart).setOnClickListener(this); 60 | findViewById(R.id.buttonStop).setOnClickListener(this); 61 | findViewById(R.id.buttonSettings).setOnClickListener(this); 62 | 63 | this.checkPermissions(this); 64 | } 65 | 66 | @Override 67 | public void onResume() { 68 | super.onResume(); 69 | 70 | this.manager.registerReceiver(this.localReceiver, new IntentFilter(TileService.ACTION_RUNNING)); 71 | 72 | // will be evaluated in the local broadcast 73 | this.running = false; 74 | this.manager.sendBroadcastSync(new Intent(TileService.ACTION_PING)); 75 | 76 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); 77 | this.serverPort = Integer.parseInt(prefs.getString("serverport", getResources().getString(R.string.settings_server_port_default))); 78 | this.rootPath = prefs.getString("rootpath", getResources().getString(R.string.settings_root_path_default)); 79 | 80 | this.prepareUI(); 81 | } 82 | 83 | @Override 84 | protected void onPause() { 85 | super.onPause(); 86 | this.manager.unregisterReceiver(this.localReceiver); 87 | } 88 | 89 | @Override 90 | public void onClick(View v) { 91 | switch (v.getId()) { 92 | case R.id.buttonStart: 93 | this.startTileService(); 94 | break; 95 | case R.id.buttonStop: 96 | this.stopTileService(); 97 | break; 98 | case R.id.buttonSettings: 99 | // OPEN settings dialog 100 | Intent preferencesIntent = new Intent(this, SettingsActivity.class); 101 | startActivity(preferencesIntent); 102 | break; 103 | default: 104 | break; 105 | } 106 | } 107 | 108 | private void startTileService() { 109 | Intent startServerIntent = new Intent(this, TileServiceReceiver.class); 110 | startServerIntent.setAction(TileServiceReceiver.ACTION_START); 111 | startServerIntent.putExtra(TileService.KEY_SERVER_PORT, this.serverPort); 112 | startServerIntent.putExtra(TileService.KEY_ROOT_PATH, this.rootPath); 113 | 114 | sendBroadcast(startServerIntent); 115 | 116 | this.running = true; 117 | 118 | this.prepareUI(); 119 | } 120 | 121 | private void stopTileService() { 122 | Intent stopServerIntent = new Intent(this, TileServiceReceiver.class); 123 | stopServerIntent.setAction(TileServiceReceiver.ACTION_STOP); 124 | 125 | sendBroadcast(stopServerIntent); 126 | 127 | this.running = false; 128 | 129 | this.prepareUI(); 130 | } 131 | 132 | @Override 133 | public boolean onCreateOptionsMenu(Menu menu) { 134 | MenuInflater inflater = getMenuInflater(); 135 | inflater.inflate(R.menu.main_menu, menu); 136 | return true; 137 | } 138 | 139 | @Override 140 | public boolean onOptionsItemSelected(MenuItem item) { 141 | if (R.id.startInfo == item.getItemId()) { 142 | Intent intent = new Intent(this, InfoActivity.class); 143 | startActivity(intent); 144 | } 145 | return true; 146 | } 147 | 148 | private void prepareUI() { 149 | ImageView buttonTile = findViewById(R.id.imageTiles); 150 | MaterialButton buttonStart = (MaterialButton) findViewById(R.id.buttonStart); 151 | MaterialButton buttonStop = (MaterialButton) findViewById(R.id.buttonStop); 152 | 153 | if (this.running) { 154 | buttonTile.setImageAlpha(255); 155 | 156 | buttonStart.setAlpha(.3f); 157 | buttonStop.setAlpha(1f); 158 | 159 | buttonStart.setClickable(false); 160 | buttonStop.setClickable(true); 161 | } else { 162 | buttonTile.setImageAlpha(50); 163 | 164 | buttonStart.setAlpha(1f); 165 | buttonStop.setAlpha(.3f); 166 | 167 | buttonStart.setClickable(true); 168 | buttonStop.setClickable(false); 169 | } 170 | } 171 | 172 | /** 173 | * Checks if the app has permission to read/write device storage 174 | *

175 | * If the app does not has permission then the user will be prompted to grant permissions 176 | * 177 | * @param activity this activity 178 | */ 179 | private void checkPermissions(Activity activity) { 180 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 181 | if (Environment.isExternalStorageManager()) { 182 | //startActivity(new Intent(this, MainActivity.class)); 183 | } else { 184 | //request for the permission 185 | AlertDialog alertDialog = new AlertDialog.Builder(this) 186 | .setTitle("Action required") 187 | .setMessage("This application needs access to all files on this device. Access to all files located in the root directory (set in app settings) is needed. In the next dialog find Mobile Tile Server application and give it permission to manage all files.") 188 | .setPositiveButton("OK", new DialogInterface.OnClickListener() { 189 | @Override 190 | public void onClick(DialogInterface dialogInterface, int i) { 191 | Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); 192 | Uri uri = Uri.fromParts("package", getPackageName(), null); 193 | intent.setData(uri); 194 | startActivity(intent); 195 | } 196 | }) 197 | .setNegativeButton("No", new DialogInterface.OnClickListener() { 198 | @Override 199 | public void onClick(DialogInterface dialogInterface, int i) { 200 | Toast.makeText(getApplicationContext(),"Permission not given! The tile server will serve only static map tiles.",Toast.LENGTH_LONG).show(); 201 | } 202 | }) 203 | .show(); 204 | } 205 | } else { 206 | //below android 11 207 | int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE); 208 | 209 | if (PackageManager.PERMISSION_GRANTED != permission) { 210 | // ask user for permissions 211 | ActivityCompat.requestPermissions( 212 | activity, 213 | PERMISSIONS_STORAGE, 214 | REQUEST_EXTERNAL_STORAGE 215 | ); 216 | } 217 | } 218 | 219 | } 220 | 221 | /** 222 | * This local broadcast is used to simply ping {@link TileService} to see if 223 | * it is running 224 | */ 225 | protected BroadcastReceiver localReceiver = new BroadcastReceiver() { 226 | @Override 227 | public void onReceive(Context context, Intent intent) { 228 | if (TileService.ACTION_RUNNING.equals(intent.getAction())) { 229 | running = true; 230 | } 231 | } 232 | }; 233 | } 234 | -------------------------------------------------------------------------------- /app/src/main/java/com/bojko108/mobiletileserver/SettingsActivity.java: -------------------------------------------------------------------------------- 1 | package com.bojko108.mobiletileserver; 2 | 3 | import android.content.DialogInterface; 4 | import android.os.Bundle; 5 | import android.text.InputType; 6 | import android.widget.EditText; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.preference.EditTextPreference; 10 | import androidx.preference.Preference; 11 | import androidx.preference.PreferenceManager; 12 | import androidx.appcompat.app.AppCompatActivity; 13 | import androidx.preference.PreferenceFragmentCompat; 14 | 15 | import com.bojko108.mobiletileserver.utils.BatteryOptimization; 16 | import com.google.android.material.dialog.MaterialAlertDialogBuilder; 17 | 18 | 19 | public class SettingsActivity extends AppCompatActivity { 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | setContentView(R.layout.activity_settings); 24 | getSupportFragmentManager() 25 | .beginTransaction() 26 | .replace(R.id.content, new SettingsFragment()) 27 | .commit(); 28 | } 29 | 30 | public static class SettingsFragment extends PreferenceFragmentCompat implements Preference.OnPreferenceClickListener, EditTextPreference.OnBindEditTextListener { 31 | @Override 32 | public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 33 | setPreferencesFromResource(R.xml.preferences, rootKey); 34 | findPreference(getString(R.string.settings_open_settings_button)).setOnPreferenceClickListener(this); 35 | findPreference(getString(R.string.settings_reset_button)).setOnPreferenceClickListener(this); 36 | findPreference(getString(R.string.rootpath)).setOnPreferenceClickListener(this); 37 | 38 | ((EditTextPreference) getPreferenceManager().findPreference(getResources().getString(R.string.serverport))).setOnBindEditTextListener(this); 39 | } 40 | 41 | @Override 42 | public boolean onPreferenceClick(Preference preference) { 43 | if (getString(R.string.settings_reset_button).equals(preference.getKey())) { 44 | MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext()); 45 | builder.setTitle("Reset preferences") 46 | .setMessage(getString(R.string.restore_defaults)) 47 | .setNegativeButton(getString(R.string.dialog_no), null) 48 | .setPositiveButton(getString(R.string.dialog_yes), new DialogInterface.OnClickListener() { 49 | @Override 50 | public void onClick(DialogInterface dialogInterface, int i) { 51 | // restore default settings when "Reset" is clicked 52 | PreferenceManager.getDefaultSharedPreferences(getContext()).edit().clear().commit(); 53 | PreferenceManager.setDefaultValues(getContext(), R.xml.preferences, true); 54 | // close this activity so the settings get updated 55 | getActivity().finish(); 56 | } 57 | }) 58 | .create(); 59 | 60 | builder.show(); 61 | } else if (getString(R.string.settings_open_settings_button).equals(preference.getKey())) { 62 | BatteryOptimization.openSettings(getContext()); 63 | } 64 | 65 | return true; 66 | } 67 | 68 | @Override 69 | public void onBindEditText(@NonNull EditText editText) { 70 | editText.setInputType(InputType.TYPE_CLASS_NUMBER); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/com/bojko108/mobiletileserver/ShortcutsActivity.java: -------------------------------------------------------------------------------- 1 | package com.bojko108.mobiletileserver; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.content.SharedPreferences; 6 | import android.os.Bundle; 7 | import android.preference.PreferenceManager; 8 | 9 | import com.bojko108.mobiletileserver.server.TileService; 10 | import com.bojko108.mobiletileserver.server.TileServiceReceiver; 11 | 12 | public class ShortcutsActivity extends Activity { 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | 18 | Intent intent = new Intent(this, TileServiceReceiver.class); 19 | 20 | if (TileServiceReceiver.ACTION_START.equals(getIntent().getAction())) { 21 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); 22 | int serverPort = Integer.parseInt(prefs.getString("serverport", getResources().getString(R.string.settings_server_port_default))); 23 | String rootPath = prefs.getString("rootpath", getResources().getString(R.string.settings_root_path_default)); 24 | 25 | intent.setAction(TileServiceReceiver.ACTION_START); 26 | intent.putExtra(TileService.KEY_SERVER_PORT, serverPort); 27 | intent.putExtra(TileService.KEY_ROOT_PATH, rootPath); 28 | } else if (TileServiceReceiver.ACTION_STOP.equals(getIntent().getAction())) { 29 | intent.setAction(TileServiceReceiver.ACTION_STOP); 30 | } 31 | 32 | if (intent.getAction() != null) { 33 | sendBroadcast(intent); 34 | } 35 | 36 | finish(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/bojko108/mobiletileserver/server/TileService.java: -------------------------------------------------------------------------------- 1 | package com.bojko108.mobiletileserver.server; 2 | 3 | import android.app.Notification; 4 | import android.app.NotificationChannel; 5 | import android.app.NotificationManager; 6 | import android.app.PendingIntent; 7 | import android.app.Service; 8 | import android.content.BroadcastReceiver; 9 | import android.content.Context; 10 | import android.content.Intent; 11 | import android.content.IntentFilter; 12 | import android.graphics.Color; 13 | import android.graphics.drawable.Icon; 14 | import android.os.Build; 15 | import android.os.IBinder; 16 | import android.util.Log; 17 | 18 | import com.bojko108.mobiletileserver.MainActivity; 19 | import com.bojko108.mobiletileserver.R; 20 | 21 | import androidx.annotation.Nullable; 22 | 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | import androidx.localbroadcastmanager.content.LocalBroadcastManager; 27 | 28 | /** 29 | * This service controls the Mobile Tile Server. Use {@link TileServiceReceiver TileServiceReceiver class} 30 | * for more info about interacting with this service. For more info regarding the HTTP Server go to 31 | * {@link TileServer TileServer class}. 32 | *

33 | * Startup parameters: 34 | * 39 | *

40 | * Mobile Tile Server, Copyright (c) 2020 by bojko108 41 | *

42 | */ 43 | public class TileService extends Service { 44 | private static final String TAG = TileService.class.getName(); 45 | /** 46 | * Use this key to trigger ping action to see if {@link TileService} is running. 47 | * A receiver is registered in {@link TileService} to listen for this action and 48 | * to broadcast {@link TileService#ACTION_RUNNING} task if the service is running. 49 | */ 50 | public static final String ACTION_PING = "mobiletileserver.ACTION_PING"; 51 | /** 52 | * Use this key to register a local receiver which will help you to determine if {@link TileService} 53 | * is running. First register a local receiver with {@link IntentFilter} set to this action 54 | * and then broadcast {@link TileService#ACTION_PING} to trigger the process. 55 | */ 56 | public static final String ACTION_RUNNING = "mobiletileserver.ACTION_RUNNING"; 57 | 58 | /** 59 | * Use this key to set the server URL address as String 60 | */ 61 | public static final String KEY_SERVER_PATH = "KEY_SERVER_PATH"; 62 | /** 63 | * Use this key to set the server listening port as int 64 | */ 65 | public static final String KEY_SERVER_PORT = "KEY_SERVER_PORT"; 66 | /** 67 | * Use this key to set the server root directory path as String 68 | */ 69 | public static final String KEY_ROOT_PATH = "KEY_ROOT_PATH"; 70 | 71 | /** 72 | * NotificationChannel used by this Service 73 | */ 74 | private NotificationChannel notificationChannel; 75 | /** 76 | * Reference to the HTTP Server 77 | */ 78 | private TileServer server; 79 | 80 | @Override 81 | public void onCreate() { 82 | super.onCreate(); 83 | 84 | Log.i(TAG, "onCreate"); 85 | } 86 | 87 | @Nullable 88 | @Override 89 | public IBinder onBind(Intent intent) { 90 | return null; 91 | } 92 | 93 | @Override 94 | public int onStartCommand(Intent intent, int flags, int startId) { 95 | super.onStartCommand(intent, flags, startId); 96 | 97 | Log.i(TAG, "onStartCommand"); 98 | try { 99 | LocalBroadcastManager.getInstance(this).registerReceiver(this.localReceiver, new IntentFilter(ACTION_PING)); 100 | 101 | if (this.server == null) { 102 | String rootPath = intent.getStringExtra(KEY_ROOT_PATH); 103 | int port = intent.getIntExtra(KEY_SERVER_PORT, 9999); 104 | 105 | this.server = new TileServer(rootPath, getApplicationContext()); 106 | this.server.start(port); 107 | 108 | startForeground(1, this.createNotification()); 109 | } 110 | } catch (Exception e) { 111 | Log.e(TAG, "onStartCommand throws: ", e); 112 | } 113 | 114 | return START_REDELIVER_INTENT; 115 | } 116 | 117 | @Override 118 | public void onDestroy() { 119 | super.onDestroy(); 120 | 121 | Log.i(TAG, "onDestroy"); 122 | 123 | LocalBroadcastManager.getInstance(this).unregisterReceiver(this.localReceiver); 124 | 125 | if (this.server != null) { 126 | this.server.stop(); 127 | } 128 | 129 | stopForeground(true); 130 | } 131 | 132 | /** 133 | * Creates a notification channel for this service 134 | */ 135 | private void createNotificationChannel() { 136 | this.notificationChannel = new NotificationChannel(TAG, getResources().getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH); 137 | this.notificationChannel.setLightColor(Color.WHITE); 138 | this.notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); 139 | this.notificationChannel.setSound(null, null); 140 | NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 141 | assert manager != null; 142 | manager.createNotificationChannel(this.notificationChannel); 143 | } 144 | 145 | /** 146 | * Creates a new notification to the notification channel 147 | * 148 | * @return notification 149 | */ 150 | private Notification createNotification() { 151 | if (this.notificationChannel == null) { 152 | this.createNotificationChannel(); 153 | } 154 | 155 | Intent openIntent = new Intent(this, MainActivity.class); 156 | openIntent.setAction(Intent.ACTION_MAIN); 157 | openIntent.addCategory(Intent.CATEGORY_LAUNCHER); 158 | 159 | PendingIntent pendingIntentNotification = PendingIntent 160 | .getActivity(this, 0, openIntent, PendingIntent.FLAG_IMMUTABLE); 161 | 162 | Notification.Action stopAction = this.createAction( 163 | TileServiceReceiver.ACTION_STOP, getResources().getString(R.string.server_action_stop_short), null, PendingIntent.FLAG_IMMUTABLE); 164 | 165 | List extras = new ArrayList<>(); 166 | extras.add(new String[]{KEY_ROOT_PATH, this.server.getRootDirectoryPath()}); 167 | Notification.Action browseRootAction = this.createAction( 168 | TileServiceReceiver.ACTION_OPEN_ROOT_PATH, getResources().getString(R.string.server_action_browse_short), extras, PendingIntent.FLAG_IMMUTABLE); 169 | 170 | extras.clear(); 171 | extras.add(new String[]{KEY_SERVER_PATH, this.server.getHomeAddress()}); 172 | Notification.Action navigateAction = this.createAction( 173 | TileServiceReceiver.ACTION_NAVIGATE_TO_SERVER, getResources().getString(R.string.server_action_navigate_short), extras, PendingIntent.FLAG_IMMUTABLE); 174 | 175 | Notification.Builder builder = new Notification.Builder(this, this.notificationChannel.getId()) 176 | .setOngoing(true) 177 | .setCategory(Notification.CATEGORY_SERVICE) 178 | .setSmallIcon(R.drawable.ic_stat_name) 179 | .setColor(getResources().getColor(R.color.colorPrimary, null)) 180 | .setContentTitle(getResources().getString(R.string.app_not_title)).setContentText(getResources().getText(R.string.app_not_text)) 181 | .addAction(navigateAction) 182 | .addAction(browseRootAction) 183 | .addAction(stopAction) 184 | .setContentIntent(pendingIntentNotification); 185 | 186 | return builder.build(); 187 | } 188 | 189 | /** 190 | * Creates new notification action 191 | * 192 | * @param actionType According to {@link TileServiceReceiver TileServiceReceiver class} 193 | * @param title Text to use for the button 194 | * @param extras List of extra values, which will be passed to the Intent, triggered by this action, 195 | * according to {@link TileServiceReceiver TileServiceReceiver class} 196 | * @param flags May be 0, {@link PendingIntent#FLAG_ONE_SHOT}, {@link PendingIntent#FLAG_NO_CREATE}, 197 | * {@link PendingIntent#FLAG_CANCEL_CURRENT}, {@link PendingIntent#FLAG_UPDATE_CURRENT}, 198 | * {@link PendingIntent#FLAG_IMMUTABLE} or any of the flags as supported by Intent.fillIn() 199 | * @return new notification action 200 | */ 201 | private Notification.Action createAction(String actionType, String title, List extras, int flags) { 202 | Intent actionIntent = new Intent(this, TileServiceReceiver.class); 203 | actionIntent.setAction(actionType); 204 | if (extras != null) { 205 | for (String[] data : extras) { 206 | actionIntent.putExtra(data[0], data[1]); 207 | } 208 | } 209 | int uniqueId = (int) (System.currentTimeMillis() & 0xfffffff); 210 | PendingIntent pendingIntentAction = PendingIntent 211 | .getBroadcast(this, uniqueId, actionIntent, flags); 212 | 213 | return new Notification.Action.Builder( 214 | Icon.createWithResource(this, R.drawable.ic_stat_name), 215 | title, 216 | pendingIntentAction).build(); 217 | } 218 | 219 | /** 220 | * This receiver is used only for broadcasting the server's running status. 221 | * First broadcast {@link TileService#ACTION_PING} and if the server is running, 222 | * this local broadcast will receive the message and will itself broadcast 223 | * {@link TileService#ACTION_RUNNING}. 224 | */ 225 | private BroadcastReceiver localReceiver = new BroadcastReceiver() { 226 | @Override 227 | public void onReceive(Context context, Intent intent) { 228 | if (ACTION_PING.equals(intent.getAction())) { 229 | LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getApplicationContext()); 230 | manager.sendBroadcast(new Intent(ACTION_RUNNING)); 231 | } 232 | } 233 | }; 234 | } 235 | -------------------------------------------------------------------------------- /app/src/main/java/com/bojko108/mobiletileserver/server/TileServiceReceiver.java: -------------------------------------------------------------------------------- 1 | package com.bojko108.mobiletileserver.server; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.net.Uri; 7 | import android.widget.Toast; 8 | 9 | /** 10 | * This class receives action requests for the TileService class 11 | * 12 | * Available Actions: 13 | *

18 | * 19 | * @see TileService TileServer class 20 | *

21 | * Mobile Tile Server, Copyright (c) 2020 by bojko108 22 | *

23 | */ 24 | public class TileServiceReceiver extends BroadcastReceiver { 25 | /** 26 | * Use this key to trigger Start Server action as String 27 | */ 28 | public static final String ACTION_START = "mobiletileserver.ACTION_START"; 29 | /** 30 | * Use this key to trigger Stop Server action as String 31 | */ 32 | public static final String ACTION_STOP = "mobiletileserver.ACTION_STOP"; 33 | /** 34 | * Use this key to trigger Open Root Directory action in FileExplorer as String 35 | */ 36 | public static final String ACTION_OPEN_ROOT_PATH = "mobiletileserver.ACTION_OPEN_ROOT_PATH"; 37 | /** 38 | * Use this key to trigger Open Server Home Page action in WebBrowser as String 39 | */ 40 | public static final String ACTION_NAVIGATE_TO_SERVER = "mobiletileserver.ACTION_NAVIGATE_TO_SERVER"; 41 | 42 | @Override 43 | public void onReceive(Context context, Intent intent) { 44 | String action = intent.getAction(); 45 | if (action != null) { 46 | try { 47 | String serverUrl = intent.getStringExtra(TileService.KEY_SERVER_PATH); 48 | String rootPath = intent.getStringExtra(TileService.KEY_ROOT_PATH); 49 | int serverPort = intent.getIntExtra(TileService.KEY_SERVER_PORT, 1886); 50 | switch (action) { 51 | case ACTION_START: 52 | Intent serviceToStart = new Intent(context, TileService.class); 53 | serviceToStart.putExtra(TileService.KEY_SERVER_PORT, serverPort); 54 | serviceToStart.putExtra(TileService.KEY_ROOT_PATH, rootPath); 55 | context.startService(serviceToStart); 56 | break; 57 | case ACTION_STOP: 58 | Intent serviceToStop = new Intent(context, TileService.class); 59 | context.stopService(serviceToStop); 60 | break; 61 | case ACTION_OPEN_ROOT_PATH: 62 | if (rootPath != null) { 63 | Uri selectedUri = Uri.parse(rootPath); 64 | Intent explorerIntent = new Intent(Intent.ACTION_VIEW); 65 | explorerIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 66 | explorerIntent.setDataAndType(selectedUri, "resource/folder"); 67 | if (explorerIntent.resolveActivityInfo(context.getPackageManager(), 0) != null) { 68 | context.startActivity(explorerIntent); 69 | this.closeNotificationBar(context); 70 | } 71 | } 72 | break; 73 | case ACTION_NAVIGATE_TO_SERVER: 74 | if (serverUrl != null) { 75 | Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(serverUrl)); 76 | browserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 77 | context.startActivity(browserIntent); 78 | this.closeNotificationBar(context); 79 | } 80 | break; 81 | default: 82 | break; 83 | } 84 | } catch (Exception ex) { 85 | Toast.makeText(context, ex.getMessage(), Toast.LENGTH_LONG).show(); 86 | } 87 | } 88 | } 89 | 90 | /** 91 | * Broadcasts Intent.ACTION_CLOSE_SYSTEM_DIALOGS message, which will close the notification bar. 92 | * 93 | * @param context context to be used for broadcasting Intent.ACTION_CLOSE_SYSTEM_DIALOGS message 94 | */ 95 | private void closeNotificationBar(Context context) { 96 | //context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); 97 | } 98 | } -------------------------------------------------------------------------------- /app/src/main/java/com/bojko108/mobiletileserver/server/tilesets/MBTilesDatabase.java: -------------------------------------------------------------------------------- 1 | package com.bojko108.mobiletileserver.server.tilesets; 2 | 3 | import java.util.Locale; 4 | 5 | import android.content.Context; 6 | import android.database.Cursor; 7 | import android.database.sqlite.SQLiteDatabase; 8 | import android.database.sqlite.SQLiteOpenHelper; 9 | 10 | import androidx.annotation.Nullable; 11 | 12 | public class MBTilesDatabase extends SQLiteOpenHelper { 13 | private static final String GET_TILE_SQL_STRING = "SELECT \"tile_data\" FROM \"tiles\" where zoom_level = %d and tile_column=%d and tile_row=%d"; 14 | private static final String GET_INFO_SQL_STRING = "SELECT * FROM \"metadata\""; 15 | 16 | private TilesetInfo info; 17 | 18 | public MBTilesDatabase(Context context, String databaseName) { 19 | super(context, databaseName, null, 1); 20 | this.info = this.readInfo(databaseName); 21 | } 22 | 23 | @Override 24 | public void onCreate(SQLiteDatabase db) { 25 | } 26 | 27 | @Override 28 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 29 | } 30 | 31 | public TilesetInfo getInfo() { 32 | return this.info; 33 | } 34 | 35 | public byte[] getTile(int z, int x, int y) { 36 | byte[] result = null; 37 | SQLiteDatabase db = this.getReadableDatabase(); 38 | 39 | // MBTiles by default use TMS for the tiles. Most mapping apps use slippy maps: XYZ schema. 40 | // We need to handle both. 41 | if (y > 0) { 42 | y = (int) Math.pow(2, z) - Math.abs(y) - 1; 43 | } else { 44 | y = Math.abs(y); 45 | } 46 | 47 | String sql = String.format(Locale.getDefault(), GET_TILE_SQL_STRING, z, x, y); 48 | 49 | try (Cursor cur = db.rawQuery(sql, null)) { 50 | cur.moveToFirst(); 51 | if (!cur.isAfterLast()) { 52 | result = cur.getBlob(0); 53 | } 54 | } catch (Exception ex) { 55 | ex.printStackTrace(); 56 | } 57 | 58 | return result; 59 | } 60 | 61 | private TilesetInfo readInfo(String fileName) { 62 | SQLiteDatabase db = this.getReadableDatabase(); 63 | String[] path = fileName.split("/"); 64 | 65 | TilesetInfo info = new TilesetInfo(); 66 | info.setParameter(TilesetInfo.TILESET_NAME, path[path.length - 1]); 67 | 68 | try (Cursor cur = db.rawQuery(GET_INFO_SQL_STRING, null)) { 69 | cur.moveToFirst(); 70 | while (!cur.isAfterLast()) { 71 | String name = cur.getString(cur.getColumnIndex("name")); 72 | String value = cur.getString(cur.getColumnIndex("value")); 73 | info.setParameter(name, value); 74 | cur.moveToNext(); 75 | } 76 | } catch (Exception ex) { 77 | ex.printStackTrace(); 78 | } 79 | 80 | return info; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/bojko108/mobiletileserver/server/tilesets/StaticFileInfo.java: -------------------------------------------------------------------------------- 1 | package com.bojko108.mobiletileserver.server.tilesets; 2 | 3 | import android.text.format.Formatter; 4 | import android.webkit.MimeTypeMap; 5 | 6 | import com.bojko108.mobiletileserver.utils.HelperClass; 7 | 8 | import java.io.File; 9 | import java.util.Locale; 10 | 11 | /** 12 | * This class provides information about a static file, served by this server. 13 | *

14 | * Mobile Tile Server, Copyright (c) 2020 by bojko108 15 | *

16 | */ 17 | public class StaticFileInfo { 18 | private File file; 19 | 20 | public StaticFileInfo(String path) { 21 | this.file = HelperClass.getFileFromPath(path); 22 | } 23 | 24 | public StaticFileInfo(File file) { 25 | this.file = file; 26 | } 27 | 28 | public String getFileName() { 29 | return this.file.getName(); 30 | } 31 | 32 | public String getFileNameWithoutExtension() { 33 | String extension = MimeTypeMap.getFileExtensionFromUrl(file.getAbsolutePath()); 34 | return this.getFileName().replace(extension, ""); 35 | } 36 | 37 | public String getContentType() { 38 | return HelperClass.getContentTypeForFile(this.file); 39 | } 40 | 41 | public long getFileSize() { 42 | return this.file.length(); 43 | } 44 | 45 | public String getSizeAsText() { 46 | String units = "B"; 47 | long bytes = this.getFileSize(); 48 | 49 | if (bytes >= 1024) { 50 | bytes = bytes / 1024; // to KB 51 | units = "KB"; 52 | } 53 | 54 | return String.format(Locale.getDefault(), "%d %s", bytes, units); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/bojko108/mobiletileserver/server/tilesets/TilesetInfo.java: -------------------------------------------------------------------------------- 1 | package com.bojko108.mobiletileserver.server.tilesets; 2 | 3 | import com.bojko108.mobiletileserver.utils.HelperClass; 4 | 5 | import org.json.JSONException; 6 | import org.json.JSONObject; 7 | 8 | import java.io.File; 9 | 10 | /** 11 | * This class provides access to various parameters for the tileset stored in 12 | * a MBTiles Database {@link MBTilesDatabase} or a directory with map tiles files. 13 | * Provided parameters from the tileset include: 14 | *

25 | *

26 | * Mobile Tile Server, Copyright (c) 2020 by bojko108 27 | *

28 | */ 29 | public class TilesetInfo { 30 | /** 31 | * Use this key to get/set tileset name 32 | */ 33 | public static final String TILESET_NAME = "tilesetname"; 34 | /** 35 | * Use this key to get/set tileset name parameter from MBTiles Database 36 | */ 37 | public static final String NAME = "name"; 38 | /** 39 | * Use this key to get/set tileset description parameter from MBTiles Database 40 | */ 41 | public static final String DESCRIPTION = "description"; 42 | /** 43 | * Use this key to get/set tileset version parameter from MBTiles Database: 1.1, 1.2, 1.3... 44 | */ 45 | public static final String VERSION = "version"; 46 | /** 47 | * Use this key to get/set tileset type parameter from MBTiles Database: png, pbf... 48 | */ 49 | public static final String FORMAT = "format"; 50 | /** 51 | * Use this key to get/set tileset min zoom parameter 52 | * Specifies the lowest zoom level for which the tileset provides data. 53 | */ 54 | public static final String MIN_ZOOM = "minzoom"; 55 | /** 56 | * Use this key to get/set tileset max zoom parameter. 57 | * Specifies the highest zoom level for which the tileset provides data. 58 | */ 59 | public static final String MAX_ZOOM = "maxzoom"; 60 | /** 61 | * Use this key to set tileset extent in geographic coordinates: 62 | * longitude_min, latitude_min, longitude_max, latitude_max. 63 | * When this parameter is set, the value of {@link TilesetInfo#getCenter()} 64 | * is also calculated. To get the value of bounds parameter use {@link TilesetInfo#getBounds()} 65 | */ 66 | public static final String BOUNDS = "bounds"; 67 | 68 | private String tilesetName = ""; 69 | private String name = ""; 70 | private String description = ""; 71 | private String format = "png"; 72 | private String version = ""; 73 | private int minZoom = 999; 74 | private int maxZoom = -1; 75 | private double[] bounds; 76 | private double[] center; 77 | 78 | public TilesetInfo() { 79 | this(null); 80 | } 81 | 82 | public TilesetInfo(File directory) { 83 | /** 84 | * Default values are set to the extent of Bulgaria! 85 | */ 86 | this.bounds = new double[4]; 87 | this.bounds[0] = 22; 88 | this.bounds[1] = 40.5; 89 | this.bounds[2] = 28; 90 | this.bounds[3] = 45; 91 | this.center = this.calculateCenter(); 92 | 93 | if (directory != null) { 94 | this.tilesetName = directory.getName(); 95 | 96 | // calculate min and max zoom for this tileset 97 | // from the subdirectories with zoom levels 98 | File[] dirs = HelperClass.getDirectoriesFrom(directory); 99 | for (File dir : dirs) { 100 | int zoomLevel = Integer.parseInt(dir.getName()); 101 | maxZoom = Math.max(maxZoom, zoomLevel); 102 | minZoom = Math.min(minZoom, zoomLevel); 103 | } 104 | } 105 | } 106 | 107 | /** 108 | * Get a parameter from the tileset. 109 | * 110 | * @param name of the parameter to return: {@link TilesetInfo#NAME}, 111 | * {@link TilesetInfo#DESCRIPTION}, {@link TilesetInfo#VERSION}, 112 | * {@link TilesetInfo#MIN_ZOOM} or {@link TilesetInfo#MAX_ZOOM}. 113 | * @return parameter value 114 | */ 115 | public T getParameter(String name, Class type) { 116 | switch (name) { 117 | case TILESET_NAME: 118 | return type.cast(this.tilesetName); 119 | case NAME: 120 | return type.cast(this.name); 121 | case DESCRIPTION: 122 | return type.cast(this.description); 123 | case FORMAT: 124 | return type.cast((this.format)); 125 | case VERSION: 126 | return type.cast(this.version); 127 | case MIN_ZOOM: 128 | return type.cast(this.minZoom); 129 | case MAX_ZOOM: 130 | return type.cast(this.maxZoom); 131 | } 132 | 133 | return null; 134 | } 135 | 136 | /** 137 | * Set a parameter for the tileset. 138 | * 139 | * @param name of the parameter to set: {@link TilesetInfo#NAME}, 140 | * {@link TilesetInfo#DESCRIPTION}, {@link TilesetInfo#VERSION}, 141 | * {@link TilesetInfo#MIN_ZOOM}, {@link TilesetInfo#MAX_ZOOM} or 142 | * {@link TilesetInfo#BOUNDS}. 143 | * @param value to set for the parameter 144 | */ 145 | public void setParameter(String name, String value) { 146 | switch (name) { 147 | case TILESET_NAME: 148 | this.tilesetName = value; 149 | break; 150 | case NAME: 151 | this.name = value; 152 | break; 153 | case DESCRIPTION: 154 | this.description = value; 155 | break; 156 | case FORMAT: 157 | this.format = value; 158 | break; 159 | case VERSION: 160 | this.version = value; 161 | break; 162 | case MIN_ZOOM: 163 | this.minZoom = Integer.parseInt(value); 164 | break; 165 | case MAX_ZOOM: 166 | this.maxZoom = Integer.parseInt(value); 167 | break; 168 | case BOUNDS: 169 | this.bounds = this.readBounds(value); 170 | this.center = this.calculateCenter(); 171 | break; 172 | } 173 | } 174 | 175 | /** 176 | * Use this to get tileset extent 177 | * 178 | * @return tileset extent - longitude_min, latitude_min, longitude_max, latitude_max 179 | */ 180 | public double[] getBounds() { 181 | return this.bounds; 182 | } 183 | 184 | /** 185 | * Gets the tileset extent as text 186 | * 187 | * @return extent coordinates, separated with "," 188 | */ 189 | public String getBoundsAsString() { 190 | return HelperClass.arrayToString(this.getBounds(), ","); 191 | } 192 | /** 193 | * Gets the tileset format as content type text 194 | * 195 | * @return content type: e.g. "image/png" 196 | */ 197 | public String getContentType() { 198 | switch (this.format.toLowerCase()) { 199 | case "jpg": 200 | return "image/jpg"; 201 | case "jpeg": 202 | return "image/jpeg"; 203 | case "bmp": 204 | return "image/bmp"; 205 | case "pbf": 206 | return "application/octet-stream"; 207 | default: // png 208 | return "image/png"; 209 | } 210 | } 211 | 212 | /** 213 | * Use this to get tileset center coordinates 214 | * 215 | * @return tileset center coordinates - longitude, latitude, initial_zoom_level 216 | */ 217 | public double[] getCenter() { 218 | return this.center; 219 | } 220 | 221 | /** 222 | * Gets the center coordinates as text 223 | * 224 | * @return center coordinates, separated with "," 225 | */ 226 | public String getCenterAsString() { 227 | return HelperClass.arrayToString(this.getCenter(), ","); 228 | } 229 | 230 | /** 231 | * Returns this tileset info as JSON object. 232 | * 233 | * @return tileset info parameters in JSON 234 | */ 235 | public JSONObject toJson() { 236 | JSONObject result = new JSONObject(); 237 | try { 238 | result.put(TILESET_NAME, this.tilesetName); 239 | result.put(NAME, this.name); 240 | result.put(DESCRIPTION, this.description); 241 | result.put(FORMAT, this.format); 242 | result.put(VERSION, this.version); 243 | result.put(MIN_ZOOM, this.minZoom); 244 | result.put(MAX_ZOOM, this.maxZoom); 245 | result.put(BOUNDS, this.getBoundsAsString()); 246 | result.put("center", this.getCenterAsString()); 247 | } catch (JSONException e) { 248 | e.printStackTrace(); 249 | } 250 | return result; 251 | } 252 | 253 | /** 254 | * Reads tileset extent from a String and converts it in geographic coordinates. 255 | * 256 | * @param boundsString tileset extent value as text - 257 | * @return tileset extent value as geographic coordinates 258 | */ 259 | private double[] readBounds(String boundsString) { 260 | double[] result = new double[4]; 261 | 262 | String[] values = boundsString.split(","); 263 | for (int i = 0; i < values.length; i++) { 264 | result[i] = Double.parseDouble(values[i]); 265 | } 266 | 267 | return result; 268 | } 269 | 270 | /** 271 | * Calculates tileset center coordinates from their extent. 272 | * 273 | * @return tileset center in geographic coordinates 274 | */ 275 | private double[] calculateCenter() { 276 | double[] result = new double[3]; 277 | 278 | if (this.bounds.length == 4) { 279 | result[0] = (this.bounds[0] + this.bounds[2]) / 2; // longitude 280 | result[1] = (this.bounds[1] + this.bounds[3]) / 2; // latitude 281 | result[2] = HelperClass.getZoomLevelFromTileWidth(this.bounds[2] - this.bounds[0]); 282 | } 283 | 284 | return result; 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /app/src/main/java/com/bojko108/mobiletileserver/utils/BatteryOptimization.java: -------------------------------------------------------------------------------- 1 | package com.bojko108.mobiletileserver.utils; 2 | 3 | import android.content.ComponentName; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.content.Intent; 7 | import android.content.pm.PackageManager; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import androidx.annotation.Nullable; 13 | import androidx.appcompat.app.AlertDialog; 14 | 15 | /** 16 | * Get a dialog that informs the user to disable battery optimization for your app. 17 | *

18 | * Use the dialog like that: 19 | * final AlertDialog dialog = BatteryOptimizationUtil.getBatteryOptimizationDialog(context); 20 | * if(dialog != null) dialog.show(); 21 | *

22 | * Alter the dialog texts so that they fit your needs. You can provide additional actions that 23 | * should be performed if the positive or negative button are clicked by using the provided method: 24 | * getBatteryOptimizationDialog(Context, OnBatteryOptimizationAccepted, OnBatteryOptimizationCanceled) 25 | *

26 | * Source: https://gist.github.com/moopat/e9735fa8b5cff69d003353a4feadcdbc 27 | *

28 | * 29 | * @author Markus Deutsch @moopat 30 | */ 31 | public class BatteryOptimization { 32 | 33 | public static void openSettings(Context context) { 34 | /* 35 | * If there is no resolvable component return right away. We do not use 36 | * isBatteryOptimizationAvailable() for this check in order to avoid checking for 37 | * resolvable components twice. 38 | */ 39 | final ComponentName componentName = getResolveableComponentName(context); 40 | if (componentName == null) return; 41 | 42 | final Intent intent = new Intent(); 43 | intent.setComponent(componentName); 44 | context.startActivity(intent); 45 | } 46 | 47 | /** 48 | * Get the battery optimization dialog. 49 | * By default the dialog will send the user to the relevant activity if the positive button is 50 | * clicked, and closes the dialog if the negative button is clicked. 51 | * 52 | * @param context Context 53 | * @return the dialog or null if battery optimization is not available on this device 54 | */ 55 | @Nullable 56 | public static AlertDialog getBatteryOptimizationDialog(final Context context) { 57 | return getBatteryOptimizationDialog(context, 58 | "Open Battery Optimization", "This app needs to be removed from battery optimizations", 59 | "Cancel", "Ok", 60 | null, null); 61 | } 62 | 63 | /** 64 | * Get the battery optimization dialog. 65 | * By default the dialog will send the user to the relevant activity if the positive button is 66 | * clicked, and closes the dialog if the negative button is clicked. Callbacks can be provided 67 | * to perform additional actions on either button click. 68 | * 69 | * @param context Context 70 | * @param positiveCallback additional callback for the positive button. can be null. 71 | * @param negativeCallback additional callback for the negative button. can be null. 72 | * @return the dialog or null if battery optimization is not available on this device 73 | */ 74 | @Nullable 75 | public static AlertDialog getBatteryOptimizationDialog( 76 | final Context context, 77 | final String title, 78 | final String message, 79 | final String negativeButtonText, 80 | final String positiveButtonText, 81 | @Nullable final OnBatteryOptimizationAccepted positiveCallback, 82 | @Nullable final OnBatteryOptimizationCanceled negativeCallback) { 83 | /* 84 | * If there is no resolvable component return right away. We do not use 85 | * isBatteryOptimizationAvailable() for this check in order to avoid checking for 86 | * resolvable components twice. 87 | */ 88 | final ComponentName componentName = getResolveableComponentName(context); 89 | if (componentName == null) return null; 90 | 91 | return new AlertDialog.Builder(context) 92 | .setTitle(title) 93 | .setMessage(message) 94 | .setNegativeButton(negativeButtonText, new DialogInterface.OnClickListener() { 95 | @Override 96 | public void onClick(DialogInterface dialog, int which) { 97 | if (negativeCallback != null) 98 | negativeCallback.onBatteryOptimizationCanceled(); 99 | } 100 | }) 101 | .setPositiveButton(positiveButtonText, new DialogInterface.OnClickListener() { 102 | @Override 103 | public void onClick(DialogInterface dialog, int which) { 104 | if (positiveCallback != null) 105 | positiveCallback.onBatteryOptimizationAccepted(); 106 | 107 | final Intent intent = new Intent(); 108 | intent.setComponent(componentName); 109 | context.startActivity(intent); 110 | } 111 | }).create(); 112 | } 113 | 114 | /** 115 | * Find out if battery optimization settings are available on this device. 116 | * 117 | * @param context Context 118 | * @return true if battery optimization is available 119 | */ 120 | public static boolean isBatteryOptimizationAvailable(final Context context) { 121 | return getResolveableComponentName(context) != null; 122 | } 123 | 124 | @Nullable 125 | private static ComponentName getResolveableComponentName(final Context context) { 126 | for (ComponentName componentName : getComponentNames()) { 127 | final Intent intent = new Intent(); 128 | intent.setComponent(componentName); 129 | if (context.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) 130 | return componentName; 131 | } 132 | return null; 133 | } 134 | 135 | /** 136 | * Get a list of all known ComponentNames that provide battery optimization on different 137 | * devices. 138 | * Based on Shivam Oberoi's answer on StackOverflow: https://stackoverflow.com/a/48166241/2143225 139 | * 140 | * @return list of ComponentName 141 | */ 142 | private static List getComponentNames() { 143 | final List names = new ArrayList<>(); 144 | names.add(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity")); 145 | names.add(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity")); 146 | names.add(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity")); 147 | names.add(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity")); 148 | names.add(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity")); 149 | names.add(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")); 150 | names.add(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.startupapp.StartupAppListActivity")); 151 | names.add(new ComponentName("com.oppo.safe", "com.oppo.safe.permission.startup.StartupAppListActivity")); 152 | names.add(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity")); 153 | names.add(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.BgStartUpManager")); 154 | names.add(new ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity")); 155 | names.add(new ComponentName("com.samsung.android.lool", "com.samsung.android.sm.ui.battery.BatteryActivity")); 156 | names.add(new ComponentName("com.htc.pitroad", "com.htc.pitroad.landingpage.activity.LandingPageActivity")); 157 | names.add(new ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.MainActivity")); 158 | 159 | return names; 160 | } 161 | 162 | public interface OnBatteryOptimizationAccepted { 163 | 164 | /** 165 | * Called if the user clicks the "OK" button of the battery optimization dialog. This does 166 | * not mean that the user has performed the necessary steps to exclude the app from 167 | * battery optimizations. 168 | */ 169 | void onBatteryOptimizationAccepted(); 170 | 171 | } 172 | 173 | public interface OnBatteryOptimizationCanceled { 174 | 175 | /** 176 | * Called if the user clicks the "Cancel" button of the battery optimization dialog. 177 | */ 178 | void onBatteryOptimizationCanceled(); 179 | 180 | } 181 | 182 | } 183 | -------------------------------------------------------------------------------- /app/src/main/java/com/bojko108/mobiletileserver/utils/HelperClass.java: -------------------------------------------------------------------------------- 1 | package com.bojko108.mobiletileserver.utils; 2 | 3 | import android.text.TextUtils; 4 | import android.util.Log; 5 | import android.webkit.MimeTypeMap; 6 | 7 | import java.io.File; 8 | import java.io.FileFilter; 9 | import java.io.IOException; 10 | import java.nio.file.Files; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.Locale; 14 | 15 | import androidx.annotation.Nullable; 16 | 17 | public class HelperClass { 18 | private static final String TAG = HelperClass.class.getName(); 19 | 20 | /** 21 | * Calculates the quadkey from tile coordinates. 22 | * 23 | * @param z coordinate of a tile 24 | * @param x coordinate of a tile 25 | * @param y coordinate of a tile 26 | * @return Quadkey 27 | * @see Bing Maps Tile System 28 | */ 29 | public static String getQuadkeyFromXYZ(int z, int x, int y) { 30 | List quadKey = new ArrayList<>(); 31 | 32 | for (int i = z; i > 0; i--) { 33 | int digit = 0; 34 | int mask = 1 << (i - 1); 35 | if ((x & mask) != 0) { 36 | digit++; 37 | } 38 | if ((y & mask) != 0) { 39 | digit++; 40 | digit++; 41 | } 42 | quadKey.add(digit); 43 | } 44 | 45 | return TextUtils.join("", quadKey); 46 | } 47 | 48 | /** 49 | * Joins the elements of an array to a string 50 | * 51 | * @param array values to join in a string 52 | * @param separator string to divide the elements, default is ',' 53 | * @return array elements joined in a string with provided separator 54 | */ 55 | public static String arrayToString(double[] array, @Nullable String separator) { 56 | if (separator == null) { 57 | separator = ","; 58 | } 59 | StringBuilder sb = new StringBuilder(); 60 | for (double d : array) { 61 | sb.append(d).append(separator); 62 | } 63 | 64 | String result = sb.toString(); 65 | if (result.endsWith(separator)) { 66 | result = result.substring(0, result.length() - 1); 67 | } 68 | 69 | return result; 70 | } 71 | 72 | /** 73 | * Calculate approximate zoom level from tile size in decimal degrees. You can calculate 74 | * the size of the tile with {@link HelperClass#getTileCoordinates(int z, int x, int y)}. 75 | * 76 | * @param tileWidth tile width in decimal degrees 77 | * @return zoom level 78 | * @see https://wiki.openstreetmap.org/wiki/Zoom_levels 79 | */ 80 | public static double getZoomLevelFromTileWidth(double tileWidth) { 81 | if (270 < tileWidth && tileWidth <= 360) 82 | return 0; // 360deg whole world 83 | if (135 < tileWidth && tileWidth <= 270) 84 | return 1; // 180deg 85 | if (67.5 < tileWidth && tileWidth <= 135) 86 | return 2; // 90deg subcontinental area 87 | if (33.75 < tileWidth && tileWidth <= 67.5) 88 | return 3; // 45deg largest country 89 | if (16.88 < tileWidth && tileWidth <= 33.75) 90 | return 4; // 22.5deg 91 | if (8.44 < tileWidth && tileWidth <= 16.88) 92 | return 5; // 11.25deg large African country 93 | if (4.22 < tileWidth && tileWidth <= 8.44) 94 | return 6; // 5.625deg large European country 95 | if (2.11 < tileWidth && tileWidth <= 4.22) 96 | return 7; // 2.813deg small country, US state 97 | if (1.05 < tileWidth && tileWidth <= 2.11) 98 | return 8; // 1.406deg 99 | if (0.53 < tileWidth && tileWidth <= 1.05) 100 | return 9; // 0.703deg wide area, large metropolitan area 101 | if (0.26 < tileWidth && tileWidth <= 0.53) 102 | return 10; // 0.352deg metropolitan area 103 | if (0.13 < tileWidth && tileWidth <= 0.26) 104 | return 11; // 0.176deg city 105 | if (0.066 < tileWidth && tileWidth <= 0.13) 106 | return 12; // 0.088deg town, or city district 107 | if (0.033 < tileWidth && tileWidth <= 0.066) 108 | return 13; // 0.044deg village, or suburb 109 | if (0.017 < tileWidth && tileWidth <= 0.033) 110 | return 14; // 0.022deg 111 | if (0.008 < tileWidth && tileWidth <= 0.017) 112 | return 15; // 0.011deg small road 113 | if (0.004 < tileWidth && tileWidth <= 0.008) 114 | return 16; // 0.005deg street 115 | if (0.002 < tileWidth && tileWidth <= 0.004) 116 | return 17; // 0.003deg block, park, addresses 117 | if (0.00075 < tileWidth && tileWidth <= 0.002) 118 | return 18; // 0.001deg some buildings, trees 119 | if (0.00038 < tileWidth && tileWidth <= 0.00075) 120 | return 19; // 0.0005deg local highway and crossing details 121 | //if (deltaLongitude <= 0.00038) 122 | return 20; // 0.00025deg A mid -sized building 123 | } 124 | 125 | /** 126 | * Get geographic coordinates from tile coordinates (upper-left corner?) 127 | * 128 | * @param z zoom level 129 | * @param x coordinate of a tile 130 | * @param y coordinate of a tile 131 | * @return geographic coordinates of a tile (upper-left corner?) 132 | */ 133 | private static double[] getTileCoordinates(int z, int x, int y) { 134 | double n = Math.pow(2, z); 135 | double latitude = Math.atan(Math.sinh(Math.PI * (1 - 2 * y / n))) * 180 / Math.PI; 136 | double longitude = x / n * 360 - 180; 137 | return new double[]{latitude, longitude}; 138 | } 139 | 140 | /** 141 | * Gets all subdirectories from a directory 142 | * 143 | * @param directory from which to return subdirectories 144 | * @return list of subdirectories 145 | */ 146 | public static File[] getDirectoriesFrom(File directory) { 147 | return directory.listFiles(new FileFilter() { 148 | @Override 149 | public boolean accept(File file) { 150 | return file.isDirectory(); 151 | } 152 | }); 153 | } 154 | 155 | /** 156 | * Gets all files from a directory. Optionally, you can filter the files based 157 | * on their extension. 158 | * 159 | * @param directory from which to return files 160 | * @param validExtension files to return, default is null - all files will be returned 161 | * @return list of files, filtered by validExtension 162 | */ 163 | public static File[] getFilesFrom(File directory, @Nullable final String validExtension) { 164 | return directory.listFiles(new FileFilter() { 165 | @Override 166 | public boolean accept(File file) { 167 | if (validExtension == null) { 168 | return file.isFile(); 169 | } else { 170 | return file.getName().endsWith(validExtension); 171 | } 172 | } 173 | }); 174 | } 175 | 176 | /** 177 | * Returns the file from the specified path. 178 | * 179 | * @param path Full file path 180 | * @return File 181 | */ 182 | public static File getFileFromPath(String path) { 183 | File file = new File(path); 184 | if (file.exists() && !file.isDirectory()) { 185 | return file; 186 | } 187 | return null; 188 | } 189 | 190 | /** 191 | * Returns the MIME type for specified File. Default result is "application/octet-stream" 192 | * 193 | * @param file to process 194 | * @return MIME type 195 | */ 196 | public static String getContentTypeForFile(File file) { 197 | String extension = file != null 198 | ? MimeTypeMap.getFileExtensionFromUrl(file.getAbsolutePath()) 199 | : ""; 200 | 201 | // if (extension == null || extension.equals("")) { 202 | // return "application/octet-stream"; 203 | // } 204 | 205 | String contentType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); 206 | return contentType != null 207 | ? contentType 208 | : "application/octet-stream"; 209 | } 210 | 211 | /** 212 | * Creates a directory of a file at the specified absolute path 213 | * 214 | * @param absolutePath path to a directory or a file 215 | */ 216 | public static void createDirectory(String absolutePath) { 217 | try { 218 | File directory = new File(absolutePath); 219 | if (!directory.exists()) { 220 | Files.createDirectories(directory.toPath()); 221 | } 222 | } catch (IOException e) { 223 | Log.i(TAG, "createDirectory: unable to create directory: " + absolutePath); 224 | e.printStackTrace(); 225 | } 226 | } 227 | 228 | public static String formatException(Exception ex) { 229 | StringBuilder sb = new StringBuilder(); 230 | sb.append(String.format("%s\n", ex.toString())); 231 | for (StackTraceElement ste : ex.getStackTrace()) { 232 | sb.append(String.format(Locale.getDefault(), " at %s(%s:%d)\n", ste.getMethodName(), ste.getClassName(), ste.getLineNumber())); 233 | } 234 | return sb.toString(); 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /app/src/main/java/com/bojko108/mobiletileserver/utils/TileGrid.java: -------------------------------------------------------------------------------- 1 | package com.bojko108.mobiletileserver.utils; 2 | 3 | public class TileGrid { 4 | 5 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_not_stop.xml: -------------------------------------------------------------------------------- 1 | 7 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_stat_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/drawable-hdpi/ic_stat_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_stat_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/drawable-mdpi/ic_stat_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_stat_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/drawable-xhdpi/ic_stat_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_stat_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/drawable-xxhdpi/ic_stat_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_help_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_info_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notifications_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_start_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_stop_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sync_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/drawable/icon_info.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_tiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/drawable/img_tiles.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/shortcut_browse_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/drawable/shortcut_browse_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/shortcut_navigate_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/drawable/shortcut_navigate_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/shortcut_start_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/drawable/shortcut_start_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/shortcut_stop_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/drawable/shortcut_stop_icon.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | 24 | 25 | 35 | 36 | 48 | 49 | 59 | 60 | 71 | 72 | 82 | 83 | 93 | 94 | 104 | 105 | 116 | 117 | 127 | 128 | 139 | 140 | 150 | 151 | 161 | 162 | 172 | 173 | 184 | 185 | 195 | 196 | 207 | 208 | 218 | 219 | 229 | 230 | 240 | 241 | 242 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 21 | 22 | 32 | 33 | 43 | 44 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/menu/main_menu.xml: -------------------------------------------------------------------------------- 1 | 2 |

4 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/raw/badrequest.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mobile Tile Server - Bad Request 6 | 7 | 13 | 14 | 15 |

(400) Bad Request

16 |
{{error_message}}
17 |         
18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/raw/home.html: -------------------------------------------------------------------------------- 1 | Mobile Tile Server 2 | 3 |

Mobile Tile Server

4 |

Mobile Tile Server is a local HTTP server, serving Map Tiles from the device storage. When the server is running you can access the map tiles from different mapping applications. The application provides access to two types of tilesets:

5 | 9 |

Available HTTP routes

10 |

Get a list of all MBTiles Tilesets

11 |

Get a list of all Directory Tilesets

12 |

Get a list of all Tilesets in JSON format

13 |

Get a list of all static files

14 |

Info

15 |

The map tiles must be stored in device storage and the app should have access to the raw files. In app settings you can change the root directory, where the tilesets are stored and also the server’s listening port. When the server is running all tilesets from the root directory can be accessed using HTTP GET Requests.

16 |
17 |
18 |

⚠️ The tile server is running in background and battery optimization functions in Android can cause it to become inactive after time. In order to be able to use it for a longer periods of time it is recommended to enable manual settings for Mobile Tile Server App in Device Settings > Battery > App Launch.

19 |
20 |

Directory Tilesets

21 |

Directory Tilesets are image files stored in directories. Each zoom level (z coordinate) is stored in a separate subdirectory and each tile column (x coordinate) is stored in additional subdirectory. This is an example file structure of the root directory:

22 |
📦MobileTileServer      --> server root directory
23 |         ┣ 📂tiles
24 |         ┃ ┣ 📂default          --> tileset name
25 |         ┃ ┃ ┣ 📂1              --> zoom level (z coordinate)
26 |         ┃ ┃ ┃ ┗ 📂1            --> x coordinate
27 |         ┃ ┃ ┃ ┃ ┗ 📜0.png      --> map tile (y coordinate)
28 |         ┃ ┃ ┣ 📂2
29 |         ┃ ┃ ┃ ┗ 📂2
30 |         ┃ ┃ ┃ ┃ ┗ 📜1.png
31 |         ┃ ┃ ┃ ┗ ...
32 |         ┃ ┃ ┗ ...
33 |         ┃ ┗ ...
34 |         ┗ 📂mbtiles
35 |     
36 |

MBTiles Tilesets

37 |

MBTiles Tilesets are SQLite databases with known schema - MBTiles. This is an example file structure of the root directory:

38 |

39 |         📦MobileTileServer                                --> server root directory
40 |         ┣ 📂mbtiles
41 |         ┃ ┣ 📜glavatar-kaleto-M5000-zoom1_17.mbtiles      --> MBTiles Tileset
42 |         ┃ ┣ 📜glavatar-kaleto-orthophoto-zoom1_18.mbtiles --> MBTiles Tileset
43 |         ┃ ┗ ...
44 |         ┗ 📂tiles
45 | 
46 |     
47 |

Static files

48 |

Returns a list of all static files served by this server. This is an example file structure of the root directory:

49 |

50 |         📦MobileTileServer                                --> server root directory
51 |         ┣ 📂static
52 |         ┃ ┣ 📜cez.json                                    --> static file
53 |         ┃ ┣ 📜test.dwg                                    --> another static file
54 |         ┃ ┗ ...
55 |         ┗ 📂tiles
56 | 
57 |     
58 |

How to use in mapping applications

59 |

Mobile Geodesy App

60 |

Mobile Geodesy is a mapping application, which can be used for collecting data and navigation. The application is capable of displaying tilesets, served from this tile server. At runtime, the Mobile Geodesy App will connect to http://localhost:{port}/availabletilesets and will download the list of all available tilesets. Then in the map activity, you can select the desired tileset to load as a basemap.

61 |

OruxMaps App

62 |

OruxMaps is another mapping application with lots of tools and capabilities. The app is also capable of loading tilesets by adding the needed infromation in app’s configuration file, stored in /storage/emulated/0/oruxmaps/mapfiles/onlinemapsources.xml. There you can add additional map sources, which can be then used in the application as basemaps. This is an example:

63 |
    64 |
  1. Open the configuration file, stored in /storage/emulated/0/oruxmaps/mapfiles/onlinemapsources.xml.
  2. 65 |
  3. Add this XML to the file:
  4. 66 |
67 |
<onlinemapsource uid="FILL_UNIQUE_ID_VALUE">
68 |         <name>glavatar-kaleto-orthophoto-zoom1_18</name>
69 |         <url><![CDATA[http://localhost:1886/mbtiles?tileset=glavatar-kaleto-orthophoto-zoom1_18.mbtiles&z={z}&x={x}&y={y}]]></url>
70 |         <minzoom>1</minzoom>
71 |         <maxzoom>18</maxzoom>
72 |         <projection>MERCATORESFERICA</projection>
73 |         <cacheable>0</cacheable>
74 |         <downloadable>1</downloadable>
75 |         <maxtilesday>0</maxtilesday>
76 |         <maxthreads>0</maxthreads>
77 |         </onlinemapsource>
78 |     
79 |
    80 |
  1. Do not forget to set the correct uid value in the xml!
  2. 81 |
82 | -------------------------------------------------------------------------------- /app/src/main/res/raw/internalservererror.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mobile Tile Server - Internal Server Error 6 | 7 | 14 | 15 | 16 |

(500) Internal Server Error

17 |
{{error_message}}
18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/raw/mbtilesserviceinfo.txt: -------------------------------------------------------------------------------- 1 |
  • 2 | {{tileset_name}} - preview with Leaflet viewer 3 |
    4 |
    5 |
    Property
    6 |
    Value
    7 |
    8 |
    9 |
    Name
    10 |
    {{name}}
    11 |
    12 |
    13 |
    Version
    14 |
    {{version}}
    15 |
    16 |
    17 |
    Description
    18 |
    {{description}}
    19 |
    20 |
    21 |
    Format
    22 |
    {{format}}
    23 |
    24 |
    25 |
    Min Zoom
    26 |
    {{min_zoom}}
    27 |
    28 |
    29 |
    Max Zoom
    30 |
    {{max_zoom}}
    31 |
    32 |
    33 |
    Bounds
    34 |
    {{bounds}}
    35 |
    36 |
    37 |
    Center
    38 |
    {{center}}
    39 |
    40 |
    41 |
    For use in Mobile Geodesy
    42 |
    43 | Tilesets are automatically added to Mobile Geodesy App. Just start the tile server, open Mobile Geodesy and choose desired tileset to load it as a basemap. 44 |
    45 |
    46 |
    47 |
    For use in OruxMaps
    48 |
    49 | Add this to OruxMaps App configuration file stored in:
    50 | /storage/emulated/0/oruxmaps/mapfiles/onlinemapsources.xml
    51 | Do not forget to set the correct uid value in the xml!
    52 |
    {{oruxmaps}}
    53 |
    54 |
    55 |
    56 |
  • -------------------------------------------------------------------------------- /app/src/main/res/raw/no_tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/app/src/main/res/raw/no_tile.png -------------------------------------------------------------------------------- /app/src/main/res/raw/oruxmaps.txt: -------------------------------------------------------------------------------- 1 | 2 | {{name}} 3 | 4 | {{min_zoom}} 5 | {{max_zoom}} 6 | MERCATORESFERICA 7 | 0 8 | 1 9 | 0 10 | 0 11 | -------------------------------------------------------------------------------- /app/src/main/res/raw/preview.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Windows Tile Server Preview 6 | 7 | 10 | 11 | 25 | 26 | 27 |
    28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/raw/services.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | {{title}} 8 | 17 | 18 | 19 |

    {{header}}

    20 |

    {{details}}

    21 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/raw/staticfileinfo.txt: -------------------------------------------------------------------------------- 1 |
  • 2 | {{name}} - download file 3 |
    4 |
    5 |
    Property
    6 |
    Value
    7 |
    8 |
    9 |
    Content Type
    10 |
    {{content_type}}
    11 |
    12 |
    13 |
    Size
    14 |
    {{file_size}}
    15 |
    16 |
    17 |
  • -------------------------------------------------------------------------------- /app/src/main/res/raw/staticfiles.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | {{title}} 8 | 17 | 18 | 19 |

    {{header}}

    20 |

    {{details}}

    21 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/raw/tileserviceinfo.txt: -------------------------------------------------------------------------------- 1 |
  • 2 | {{tileset_name}} - preview with Leaflet viewer 3 |
    4 |
    5 |
    Property
    6 |
    Value
    7 |
    8 |
    9 |
    Min Zoom
    10 |
    {{min_zoom}}
    11 |
    12 |
    13 |
    Max Zoom
    14 |
    {{max_zoom}}
    15 |
    16 |
    17 |
    Bounds
    18 |
    {{bounds}} (unable to calculate, default value is returned)
    19 |
    20 |
    21 |
    Center
    22 |
    {{center}} (unable to calculate, default value is returned)
    23 |
    24 |
    25 |
    For use in Mobile Geodesy
    26 |
    27 | Tilesets are automatically added to Mobile Geodesy App. Just start the tile server, open Mobile Geodesy and choose desired tileset to load it as a basemap. 28 |
    29 |
    30 |
    31 |
    For use in OruxMaps
    32 |
    33 | Add this to OruxMaps App configuration file stored in:
    34 | /storage/emulated/0/oruxmaps/mapfiles/onlinemapsources.xml
    35 | Do not forget to set the correct uid value in the xml!
    36 |
    {{oruxmaps}}
    37 |
    38 |
    39 |
    40 |
  • -------------------------------------------------------------------------------- /app/src/main/res/values-bg-rBG/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ОК 4 | Отказ 5 | Да 6 | Не 7 | Наистина ли искате ли да възстановите настройките по подразбиране? 8 | Сървър порт 9 | Задайте порт, на който да работи сървъра 10 | Директория, съдържаща тайлове 11 | Задайте директорията, в която се съхраняват тайлове 12 | Сървърът е стартиран 13 | Възстанови 14 | Стартиране 15 | Спиране 16 | Настройки 17 | Възстановяване на началните настройки 18 | File Explorer 19 | Помощ 20 | Помощ 21 | Mobile Tile Server (v%s) може да се използва като HTTP сървър, предоставящ достъп до карти, съхранявани на мобилното устройство. При стартиран сървър, вие може да достъпвате картите от различни приложения. 22 | Приложението предоставя четири възможности:\n- Достъп до локални карти\n- Достъп до карти съхранявани във формат MBTiles\n- Пренасочване към друг картен сървър с QuadKey схема\n- Достъп до статични файлове\n\nЗа да промените картинката по подразбиране за ненамерени тайлове, \nсъздайте файл \'no_tile.png\' в основната директория с файлове. 23 | Локалните карти са достъпни на адрес: 24 | Където стойността на PORT е зададена в настройките на приложението. Директорията, в която се намират картите също трябва да бъде зададена там. Тази директория се използва като основна от сървъра. Всички файлове и поддиректории в основната директория са достъпни от сървъра. 25 | Достъп до локални карти 26 | ПРИМЕР 27 | Ако разполагате с карта, съхранявана в директория: \'/storage/emulated/0/MobileTileServer/tiles/Plovdiv/{z}_{x}_{y}.png\' можете да зададете основната директория така: \'/storage/emulated/0/MobileTileServer\'. За да достъпите тази карта стартирайте сървъра и отидете на адрес: 28 | Пренасочването е достъпно на адрес: 29 | Може да се достъпи на адрес: 30 | Ако разполагате с карти във формат MBTiles можете да ги заредите в основната директория и да ги достъпите чрез: 31 | Mobile Tile Server поддържа само GET заявки! 32 | Сървърът е стартиран! 33 | Управлявайте сървърът от тук: 34 | Спри сървъра 35 | Стартирай сървъра 36 | Спри 37 | Стартирай 38 | Отиди до 39 | Отвори 40 | Отвори файловете 41 | Отиди до 42 | Battery > App Launch:]]> 43 | Работа на заден план 44 | Отвори настройките 45 | Има няколко параметъра, които трябва да се зададат: 46 | Където стойността на PORT е зададена в настройките на приложението. Директорията, в която се намират картите също трябва да бъде зададена там. Тази директория се използва като основна от сървъра. Всички файлове и поддиректории в основната директория са достъпни от сървъра. 47 | Пренасочване към друг картен сървър с QuadKey схема 48 | Където стойността на PORT е зададена в настройките на приложението. Директорията, в която се намират картите също трябва да бъде зададена там. Тази директория се използва като основна от сървъра. Всички файлове и поддиректории в основната директория са достъпни от сървъра. 49 | Ако искате да използвате например Bing Maps, която използва QuadKey схема, но разполагате само с XYZ коориднати на картите може да използвате опцията за пренасочване, която ще калкулира QuadKey стойността и ще пренасочи заявката към съответняит сървър. За достъп до Bing Maps Aerial може да зададете адрес: 50 | Настройки 51 | -------------------------------------------------------------------------------- /app/src/main/res/values-bg/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ОК 4 | Отказ 5 | Да 6 | Не 7 | Наистина ли искате ли да възстановите настройките по подразбиране? 8 | Настройки 9 | Сървър порт 10 | Задайте порт, на който да работи сървъра 11 | Директория, съдържаща тайлове 12 | Задайте директорията, в която се съхраняват тайлове 13 | Сървърът е стартиран 14 | Възстанови 15 | Стартиране 16 | Спиране 17 | Настройки 18 | Възстановяване на началните настройки 19 | File Explorer 20 | Помощ 21 | Помощ 22 | Mobile Tile Server (v%s) може да се използва като HTTP сървър, предоставящ достъп до карти, съхранявани на мобилното устройство. При стартиран сървър, вие може да достъпвате картите от различни приложения. 23 | Приложението предоставя четири възможности:\n- Достъп до локални карти\n- Достъп до карти съхранявани във формат MBTiles\n- Пренасочване към друг картен сървър с QuadKey схема\n- Достъп до статични файлове\n\nЗа да промените картинката по подразбиране за ненамерени тайлове, \nсъздайте файл \'no_tile.png\' в основната директория с файлове. 24 | Локалните карти са достъпни на адрес: 25 | Където стойността на PORT е зададена в настройките на приложението. Директорията, в която се намират картите също трябва да бъде зададена там. Тази директория се използва като основна от сървъра. Всички файлове и поддиректории в основната директория са достъпни от сървъра. 26 | Пренасочване към друг картен сървър с QuadKey схема 27 | Достъп до локални карти 28 | ПРИМЕР 29 | Ако разполагате с карта, съхранявана в директория: \'/storage/emulated/0/MobileTileServer/tiles/Plovdiv/{z}_{x}_{y}.png\' можете да зададете основната директория така: \'/storage/emulated/0/MobileTileServer\'. За да достъпите тази карта стартирайте сървъра и отидете на адрес:\n\n\'http://localhost:PORT/tiles/Plovdiv/{z}_{x}_{y}.png\'.\n\nВ случая основната директория сочи към родителската директория (тя съдържа поддиректория \'Plovdiv\'). По този начин може да разполагате с различни карти, подредени в поддиректории и те да са достъпни на един и същи сървър! 30 | Пренасочването е достъпно на адрес: 31 | Ако искате да използвате например Bing Maps, която използва QuadKey схема, но разполагате само с XYZ коориднати на картите може да използвате опцията за пренасочване, която ще калкулира QuadKey стойността и ще пренасочи заявката към съответняит сървър. За достъп до Bing Maps Aerial може да зададете адрес:\n\n\'http://localhost:PORT/redirect/\n?url=http://ecn.t0.tiles.virtualearth.net/tiles/a{quadkey}.jpeg?g=6201\n&quadkey=true&x={x}&z={y}&z={z}\' 32 | Където стойността на PORT е зададена в настройките на приложението. Директорията, в която се намират картите също трябва да бъде зададена там. Тази директория се използва като основна от сървъра. Всички файлове и поддиректории в основната директория са достъпни от сървъра.\n\nСъществуват няколко параметъра, чиито стойности трябва да бъдат зададени:\n- \'url\': адрес, към който да се пренасочи\n- \'quadkey\': \'true\' ако сървъра използва QuadKey схема\n- \'z\': ниво на мащаба на картата\n- \'x\': x координатата на карта\n- \'y\': y координатата на карта 33 | Може да се достъпи на адрес: 34 | Има няколко параметъра, които трябва да се зададат: 35 | Където стойността на PORT е зададена в настройките на приложението. Директорията, в която се намират картите също трябва да бъде зададена там. Тази директория се използва като основна от сървъра. Всички файлове и поддиректории в основната директория са достъпни от сървъра.\n\nMBTiles използват TMS схема на пдоредба ма тайловете и y координатата трябва да се трансформира, за да се намери точният тайл. Ако картата използва XYZ схема, подайте отрицателна стойност за y (-y). \n\nИма няколко параметъра, които трябва да се зададат:\n- \'file\': име на MBTiles файл (включително разширението)\n- \'z\': ниво на мащаб на картата\n- \'x\': x координата на картата\n- \'y\': y координата на картата 36 | "Ако разполагате с карти във формат MBTiles можете да ги заредите в основната директория и да ги достъпите чрез:\n\n\'http://localhost:PORT/mbtiles/?tileset=test.mbtiles&z={z}&x={x}&y={y}\'\nили ако се използва XYZ схема:\n\'http://localhost:PORT/mbtiles/?tileset=test.mbtiles&z={z}&x={x}&y=-{y}\'" 37 | Mobile Tile Server поддържа само GET заявки! 38 | Сървърът е стартиран! 39 | Управлявайте сървърът от тук: 40 | Спри сървъра 41 | Стартирай сървъра 42 | Спри 43 | Стартирай 44 | Отиди до 45 | Отвори 46 | Отвори файловете 47 | Отиди до 48 | Battery > App Launch:]]> 49 | Работа на заден план 50 | Отвори настройките 51 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | #f00000 8 | #ba000d 9 | #333333 10 | #ffffff 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 16dp 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF1E00 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Mobile Tile Server 4 | Help 5 | Help 6 | OK 7 | Cancel 8 | Yes 9 | No 10 | Start 11 | Stop 12 | Settings 13 | Mobile Tile Server supports GET requests only! 14 | 15 | 16 | EXAMPLE 17 | Mobile Tile Server (v%s) can be used as a HTTP server, serving Map Tiles from the device storage. When the server is running you can access the tiles from different mapping applications. 18 | The application provides four options:\n- Access of local Map Tiles\n- Access of local MBTiles files\n- Redirect to a Tile Server with QuadKey Tile schema\n- Access static files\n\nTo change the default tile image put a \'no_tile.png\' file in \nthe root directory of the server. 19 | Access to local Map Tiles 20 | Local Map Tiles can be accessed on address: 21 | Where PORT is set in application settings. In settings, you must specify a directory, where the files are stored. This directory is used as a root for the server. All files in that directory (including subdirectories) will be accessible from the server. 22 | If you have map tiles stored in \'/storage/emulated/0/MobileTileServer/tiles/Plovdiv/{z}_{x}_{y}.png\', you can set the root directory to: \'/storage/emulated/0/MobileTileServer\'. Then in order to access this map just start the service and navigate to:\n\n\'http://localhost:PORT/tiles/Plovdiv/{z}_{x}_{y}.png\'.\n\nIn this case the root directory points to the parent folder (which contains \'Plovdiv\' subfolder). This way you can have multiple subfolders containing different map tiles and all can be accessed through the same server! 23 | Access to local MBTiles files 24 | Can be found on address: 25 | Where PORT is set in application settings. In settings, you must specify a directory, where the files are stored. This directory is used as a root for the server. All files in that directory (including subdirectories) will be accessible from the server.\n\nAs MBTiles use TMS schema to store map tiles, y coordinate must be transformed in order to locate the correct tile row. If your app uses XYZ tile schema, pass negative value for y (-y) as a parameter. \n\nThere are several parameters, which must be provided:\n- \'file\': MBTiles file (including extension)\n- \'z\': map zoom level\n- \'x\': x coordinate of a map tile\n- \'y\': y coordinate of a map tile 26 | If you have tiles stored in MBTiles format, you can place your files in the root directory and access them with:\n\n\'http://localhost:PORT/mbtiles/?tileset=test.mbtiles&z={z}&x={x}&y={y}\'\nor if XYZ schema is used:\n\'http://localhost:PORT/mbtiles/?tileset=test.mbtiles&z={z}&x={x}&y=-{y}\' 27 | Redirect to a Tile Server with QuadKey Tile schema 28 | Redirect can be accessed on address: 29 | Where PORT is set in application settings. In settings, you must specify a directory, where the files are stored. This directory is used as a root for the server. All files in that directory (including subdirectories) will be accessible from the server.\n\nThere are several parameters, which must be provided:\n- \'url\': url address on which to redirect\n- \'quadkey\': \'true\' if the server uses QuadKey Tile schema\n- \'z\': map zoom level\n- \'x\: x coordinate of a map tile\n- \'y\': y coordinate of a map tile 30 | If you want to use for example Bing Maps, which uses QuadKey Tile schema and you only have XYZ tile coordinates you can use the redirect option, which will calculate the quadkey value and then will redirect the request to the server. For accessing Bing Maps Aerial map tiles you can navigate to:\n\n\'http://localhost:PORT/redirect/?url=http://ecn.t0.tiles.virtualearth.net/tiles/a{quadkey}.jpeg?g=6201&quadkey=true&z={z}&x={x}&y={y}\' 31 | 32 | 33 | Settings 34 | Do you want to reset all settings to default values? 35 | Listening port 36 | Specify listening port for the tile server 37 | 1886 38 | Tiles root directory path 39 | Specify root directory path where the map tiles are stored 40 | /storage/emulated/0/MobileTileServer 41 | Tile server running 42 | Restore default settings 43 | Restore 44 | settings_reset_button 45 | pref_key_storage_settings 46 | serverport 47 | rootpath 48 | running 49 | File Explorer 50 | Up and running! 51 | Control the tile server from here: 52 | Stop Server 53 | Start Server 54 | Stop 55 | Start 56 | Navigate To 57 | Navigate 58 | Browse Files 59 | Browse 60 | Available MBTiles Tilesets 61 | This is a list of all MBTiles tilesets, served from this server: 62 | Available Directory Tilesets 63 | This is a list of all directories, containing tiles and are served from this service: 64 | Available Static Files 65 | This is a list of all static files, which are served from this service: 66 | settings_open_settings_button 67 | Battery > App Launch:]]> 68 | settings_category_open_settings 69 | Run in background 70 | Open Settings 71 | settings_open_settings_info 72 | 73 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 24 | 25 | 30 | 31 | 34 | 35 | 39 | 40 | 44 | 45 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/xml/preferences.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 17 | 18 | 22 | 27 | /> 28 | 33 | /> 34 | 35 | 36 | 40 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/xml/shortcuts.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 13 | 14 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:8.5.1' 11 | 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | google() 21 | jcenter() 22 | } 23 | } 24 | 25 | task clean(type: Delete) { 26 | delete rootProject.buildDir 27 | } 28 | -------------------------------------------------------------------------------- /docs/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/docs/01.jpg -------------------------------------------------------------------------------- /docs/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/docs/02.jpg -------------------------------------------------------------------------------- /docs/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/docs/03.jpg -------------------------------------------------------------------------------- /docs/04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/docs/04.jpg -------------------------------------------------------------------------------- /docs/05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/docs/05.jpg -------------------------------------------------------------------------------- /docs/06.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/docs/06.jpg -------------------------------------------------------------------------------- /docs/07.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/docs/07.jpg -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # How to make a bundle 2 | 3 | 1. In Android Studio - Build / Generate Signed Bundle/APK... and choose `Android App Bundle`. 4 | 2. Download [bundletool](https://github.com/google/bundletool) 5 | 6 | ```bash 7 | java -jar bundletool-all-1.12.1.jar build-apks --bundle=app-release.aab --output=app-release.apks 8 | java -jar bundletool-all-1.12.1.jar install-apks --apks=app-release.apks 9 | ``` 10 | -------------------------------------------------------------------------------- /docs/feature-graphic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/docs/feature-graphic.jpg -------------------------------------------------------------------------------- /docs/icon.cdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/docs/icon.cdr -------------------------------------------------------------------------------- /docs/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/docs/icon.png -------------------------------------------------------------------------------- /docs/no_tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/docs/no_tile.png -------------------------------------------------------------------------------- /fastlane/metadata/android/de/short_description.txt: -------------------------------------------------------------------------------- 1 | HTTP-Server für Ihre lokalen Kartenkacheln -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/full_description.txt: -------------------------------------------------------------------------------- 1 |

    Mobile Tile Server can be used as a HTTP server, serving Map Tiles from the device storage. When the server is running you can access the tiles from different mapping applications.

    The application provides four main options:

    Access to local Map Tiles

    Local Map Tiles can be accessed on address: http://localhost:PORT/tiles – where PORT is set in application settings. In settings, you must specify a directory, where the files are stored. This directory is used as a root for the server. All files in that directory (including subdirectories) will be accessible from the server.


    Example: If you have map tiles stored in /storage/emulated/0/MobileTileServer/tiles/Plovdiv/{z}_{x}_{y}.png, you can set the root directory to: /storage/emulated/0/MobileTileServer. Then in order to access this map just start the service and navigate to: http://localhost:PORT/tiles/Plovdiv/{z}_{x}_{y}.png.

    In this case the root directory points to the parent folder (which contains ’Plovdiv’ subfolder). This way you can have multiple subfolders containing different map tiles and all can be accessed through the same server!


    Access to local MBTiles files

    … can be found on address: http://localhost:PORT/mbtiles – where PORT is set in application settings. In settings, you must specify a directory, where the files are stored. This directory is used as a root for the server. All files in that directory (including subdirectories) will be accessible from the server.

    As MBTiles use TMS schema to store map tiles, y coordinate must be transformed in order to locate the correct tile row. If your app uses XYZ tile schema, pass negative value for y (-y) as a parameter.

    There are several parameters, which must be provided:

    Example: If you have tiles stored in MBTiles format, you can place your files in the root directory and access them with: http://localhost:PORT/mbtiles/?tileset=test.mbtiles&z={z}&x={x}&y={y} or if XYZ schema is used: http://localhost:PORT/mbtiles/?tileset=test.mbtiles&z={z}&x={x}&y=-{y}


    Redirect to a Tile Server with QuadKey Tile schema

    Redirect can be accessed on address: http://localhost:PORT/redirect/?url=&quadkey=true&z=&x=&y= – where PORT is set in application settings. In settings, you must specify a directory, where the files are stored. This directory is used as a root for the server. All files in that directory (including subdirectories) will be accessible from the server.

    There are several parameters, which must be provided:

    Example: If you want to use for example Bing Maps, which uses QuadKey Tile schema and you only have XYZ tile coordinates you can use the redirect option, which will calculate the quadkey value and then will redirect the request to the server. For accessing Bing Maps Aerial map tiles you can navigate to: http://localhost:PORT/redirect/?url=http://ecn.t0.tiles.virtualearth.net/tiles/a{quadkey}.jpeg?g=6201&quadkey=true&z={z}&x={x}&y={y}

    -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/featureGraphic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/fastlane/metadata/android/en-US/images/featureGraphic.jpg -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/fastlane/metadata/android/en-US/images/icon.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/fastlane/metadata/android/en-US/images/phoneScreenshots/01.jpg -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/fastlane/metadata/android/en-US/images/phoneScreenshots/02.jpg -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/fastlane/metadata/android/en-US/images/phoneScreenshots/03.jpg -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/fastlane/metadata/android/en-US/images/phoneScreenshots/04.jpg -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/fastlane/metadata/android/en-US/images/phoneScreenshots/05.jpg -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/06.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/fastlane/metadata/android/en-US/images/phoneScreenshots/06.jpg -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/07.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/fastlane/metadata/android/en-US/images/phoneScreenshots/07.jpg -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/short_description.txt: -------------------------------------------------------------------------------- 1 | HTTP Server for your local Map Tiles -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | android.defaults.buildfeatures.buildconfig=true 13 | android.enableJetifier=true 14 | android.nonFinalResIds=false 15 | android.nonTransitiveRClass=false 16 | android.useAndroidX=true 17 | org.gradle.jvmargs=-Xmx1536m 18 | 19 | # When configured, Gradle will run in incubating parallel mode. 20 | # This option should only be used with decoupled projects. More details, visit 21 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 22 | # org.gradle.parallel=true 23 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bojko108/mobile-tile-server/8d11be7393c45a08397c500ac7a854e3a8e7ddf5/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Aug 08 09:55:33 EEST 2024 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------