Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 68 additions & 45 deletions docs/MAP_TYPES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This guide helps you choose and configure the right map type for your OpenMapVie

## Quick Start

OpenMapView provides **15 map types** from various tile providers. Eleven types work without any configuration (including `NONE`), while four premium types require free API keys.
OpenMapView provides **15 map types** from various tile providers. Nine types work without any configuration (including `NONE`), while six premium types require free API keys.

```kotlin
val mapView = OpenMapView(context)
Expand Down Expand Up @@ -147,41 +147,7 @@ Contemporary design with vibrant colors and clear labels.
mapView.setMapType(MapType.CARTO_VOYAGER)
```

#### 9. STAMEN_TONER - High-Contrast Black & White
**`MapType.STAMEN_TONER`** (constant value: 13)

Stark black and white design with maximum contrast.

- **Best for**: Data visualization, marker overlays, minimalist design
- **Features**: High contrast, clear roads and boundaries
- **Highlights**: Most popular Stamen style, ideal for making colored overlays highly visible
- **Tile Server**: tiles.stadiamaps.com (Stadia Maps)
- **Max Zoom**: 20
- **Free Tier**: 200,000 tiles/month for local development
- **Attribution**: © OpenStreetMap contributors. Tiles © Stamen Design, © Stadia Maps

```kotlin
mapView.setMapType(MapType.STAMEN_TONER)
```

#### 10. STAMEN_WATERCOLOR - Artistic Watercolor Rendering
**`MapType.STAMEN_WATERCOLOR`** (constant value: 14)

Unique hand-painted watercolor aesthetic with soft colors.

- **Best for**: Creative apps, travel journals, artistic visualization
- **Features**: Hand-painted appearance, soft color palette
- **Highlights**: Artistic interpretation of geographic features, completely unique style
- **Tile Server**: tiles.stadiamaps.com (Stadia Maps)
- **Max Zoom**: 16
- **Free Tier**: 200,000 tiles/month for local development
- **Attribution**: © OpenStreetMap contributors. Tiles © Stamen Design, © Stadia Maps

```kotlin
mapView.setMapType(MapType.STAMEN_WATERCOLOR)
```

#### 11. NONE - No Base Tiles
#### 9. NONE - No Base Tiles
**`MapType.NONE`** (constant value: 0)

No base map tiles displayed (useful for custom tile sources or offline maps).
Expand All @@ -198,7 +164,7 @@ These map types require free API keys from third-party tile providers. When an A
- Keeps the map fully interactive (pan, zoom still work)
- Logs a warning to help with debugging

#### 12. CYCLEMAP - Professional Cycling Map
#### 10. CYCLEMAP - Professional Cycling Map
**`MapType.CYCLEMAP`** (constant value: 3) **Requires Thunderforest API Key**

Professional cycling map with elevation contours and comprehensive infrastructure.
Expand All @@ -224,7 +190,7 @@ ApiKeyManager.setApiKey("thunderforest", "your_key_here")
mapView.setMapType(MapType.CYCLEMAP)
```

#### 13. TRANSPORT - Public Transit Map
#### 11. TRANSPORT - Public Transit Map
**`MapType.TRANSPORT`** (constant value: 4) **Requires Thunderforest API Key**

Public transport focused map with comprehensive transit information.
Expand All @@ -243,7 +209,7 @@ Public transport focused map with comprehensive transit information.
mapView.setMapType(MapType.TRANSPORT)
```

#### 14. TRANSPORT_DARK - Dark Mode Public Transit Map
#### 12. TRANSPORT_DARK - Dark Mode Public Transit Map
**`MapType.TRANSPORT_DARK`** (constant value: 5) **Requires Thunderforest API Key**

Dark variant of the public transport map with comprehensive transit information in a dark color scheme.
Expand All @@ -262,7 +228,7 @@ Dark variant of the public transport map with comprehensive transit information
mapView.setMapType(MapType.TRANSPORT_DARK)
```

#### 15. TRACESTRACK_TOPO - Topographic Map
#### 13. TRACESTRACK_TOPO - Topographic Map
**`MapType.TRACESTRACK_TOPO`** (constant value: 6) **Requires Tracestrack API Key**

Detailed topographic map with elevation contours and hillshading.
Expand All @@ -288,6 +254,51 @@ ApiKeyManager.setApiKey("tracestrack", "your_key_here")
mapView.setMapType(MapType.TRACESTRACK_TOPO)
```

#### 14. STAMEN_TONER - High-Contrast Black & White
**`MapType.STAMEN_TONER`** (constant value: 13) **Requires Stadia Maps API Key**

Stark black and white design with maximum contrast.

- **Best for**: Data visualization, marker overlays, minimalist design
- **Features**: High contrast, clear roads and boundaries
- **Highlights**: Most popular Stamen style, ideal for making colored overlays highly visible
- **Tile Server**: tiles.stadiamaps.com (Stadia Maps)
- **Max Zoom**: 20
- **Free Tier**: 200,000 tiles/month for non-commercial use
- **Get API Key**: https://client.stadiamaps.com/signup/
- **Attribution**: © OpenStreetMap contributors. Tiles © Stamen Design, © Stadia Maps

```kotlin
// Configure in AndroidManifest.xml:
<meta-data
android:name="de.afarber.openmapview.STADIA_API_KEY"
android:value="your_key_here"/>

// Or programmatically:
ApiKeyManager.setApiKey("stadia", "your_key_here")

mapView.setMapType(MapType.STAMEN_TONER)
```

#### 15. STAMEN_WATERCOLOR - Artistic Watercolor Rendering
**`MapType.STAMEN_WATERCOLOR`** (constant value: 14) **Requires Stadia Maps API Key**

Unique hand-painted watercolor aesthetic with soft colors.

- **Best for**: Creative apps, travel journals, artistic visualization
- **Features**: Hand-painted appearance, soft color palette
- **Highlights**: Artistic interpretation of geographic features, completely unique style
- **Tile Server**: tiles.stadiamaps.com (Stadia Maps)
- **Max Zoom**: 16
- **Free Tier**: 200,000 tiles/month for non-commercial use
- **Get API Key**: https://client.stadiamaps.com/signup/
- **Attribution**: © OpenStreetMap contributors. Tiles © Stamen Design, © Stadia Maps

```kotlin
// Same API key as STAMEN_TONER
mapView.setMapType(MapType.STAMEN_WATERCOLOR)
```

## API Key Configuration

### Method 1: AndroidManifest.xml (Recommended)
Expand All @@ -305,6 +316,11 @@ Add API keys to your app's `AndroidManifest.xml`:
<meta-data
android:name="de.afarber.openmapview.TRACESTRACK_API_KEY"
android:value="your_tracestrack_key_here"/>

<!-- Stadia Maps (for STAMEN_TONER, STAMEN_WATERCOLOR and the Stamen overlays) -->
<meta-data
android:name="de.afarber.openmapview.STADIA_API_KEY"
android:value="your_stadia_key_here"/>
</application>
```

Expand All @@ -317,6 +333,7 @@ import de.afarber.openmapview.ApiKeyManager

ApiKeyManager.setApiKey("thunderforest", "your_key_here")
ApiKeyManager.setApiKey("tracestrack", "your_key_here")
ApiKeyManager.setApiKey("stadia", "your_key_here")
```

### Obtaining API Keys
Expand All @@ -334,6 +351,12 @@ All providers offer generous free tiers suitable for development and small-scale
- **Free Tier**: 100,000 tiles/month
- **Sign Up**: Register for free account

#### Stadia Maps (STAMEN_TONER, STAMEN_WATERCOLOR)
- **Website**: https://client.stadiamaps.com/signup/
- **Free Tier**: 200,000 tiles/month for non-commercial use
- **Sign Up**: Register for free account
- **One key works for**: STAMEN_TONER, STAMEN_WATERCOLOR and the Stamen overlays in `PredefinedTileProviders`

### Security Best Practices

1. **Use Domain Restrictions**: Configure API keys on provider websites to restrict usage to your app's domain/bundle ID
Expand All @@ -359,15 +382,15 @@ All providers offer generous free tiers suitable for development and small-scale
| Emergency/humanitarian | `HUMANITARIAN` |
| Data visualization (light) | `CARTO_LIGHT` |
| Night mode / dark theme | `CARTO_DARK` |
| High-contrast data viz | `STAMEN_TONER` |
| Creative/artistic app | `STAMEN_WATERCOLOR` |
| High-contrast data viz | `STAMEN_TONER` (requires API key) |
| Creative/artistic app | `STAMEN_WATERCOLOR` (requires API key) |
| Custom tiles only | `NONE` |

### Performance Considerations

- **Free maps without limits** (STANDARD, CYCLOSM, HUMANITARIAN, OPNVKARTE, OPENTOPOMAP): No usage limits, best for production apps
- **Free maps with generous limits** (CARTO_LIGHT, CARTO_DARK, CARTO_VOYAGER, STAMEN_TONER, STAMEN_WATERCOLOR): Free tiers available (75k-200k tiles/month)
- **Premium maps** with API keys (CYCLEMAP, TRANSPORT, TRANSPORT_DARK, TRACESTRACK_TOPO): Monitor monthly tile limits (free tiers: 100k-150k tiles/month)
- **Free maps with generous limits** (CARTO_LIGHT, CARTO_DARK, CARTO_VOYAGER): Free tier available (75k tiles/month)
- **Premium maps** with API keys (CYCLEMAP, TRANSPORT, TRANSPORT_DARK, TRACESTRACK_TOPO, STAMEN_TONER, STAMEN_WATERCOLOR): Monitor monthly tile limits (free tiers: 100k-200k tiles/month)
- **Tile caching**: OpenMapView automatically caches tiles in memory and on disk to minimize requests
- **Subdomain rotation**: Maps with subdomain support automatically distribute load across multiple servers for better performance

Expand All @@ -379,7 +402,7 @@ In addition to base map types, OpenMapView supports **tile overlays** that rende
- **OpenRailwayMap**: Railway infrastructure
- **OpenSnowMap**: Ski pistes, lifts
- **Waymarked Trails**: Hiking, cycling, MTB, skating trails
- **Stamen Overlays**: Labels, terrain lines
- **Stamen Overlays**: Toner and terrain lines (roads, railways, borders), need a Stadia Maps API key

See `PredefinedTileProviders.kt` for predefined overlay sources, or create custom overlays using `TileOverlay` and `UrlTileProvider`.

Expand Down
6 changes: 3 additions & 3 deletions docs/TESTING_UNIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ The `--continue` flag ensures all tests run even if some fail, useful for gettin

## Test Structure

### Current Test Coverage (458 tests across 35 test classes)
### Current Test Coverage (461 tests across 35 test classes)

| Test Class | Tests | Description |
|------------|-------|-------------|
Expand All @@ -78,14 +78,14 @@ The `--continue` flag ensures all tests run even if some fail, useful for gettin
| **OptionsBuildersTest** | 13 | Google-style *Options builders for markers, shapes and overlays |
| **PolygonTest** | 20 | Polygon creation, validation, holes, and styling |
| **PolylineTest** | 31 | Polyline creation, validation, and styling |
| **PredefinedTileProvidersTest** | 1 | URL templates of the predefined overlay tile providers |
| **PredefinedTileProvidersTest** | 2 | URL templates of the predefined overlay tile providers, Stadia key lookup |
| **ProjectionTest** | 12 | Web Mercator projection calculations |
| **SnapshotTest** | 8 | Map snapshot API and callbacks |
| **TileCacheTest** | 9 | Memory LRU cache behavior, clearing, namespaces, disk writes |
| **TileDownloaderTest** | 5 | HTTP tile downloading with mocked Ktor client, HTTP errors, cancellation |
| **TileOverlayTest** | 5 | Tile overlay defaults, transparency validation, copy helpers |
| **TileRetryTrackerTest** | 4 | Exponential backoff for failed tiles |
| **TileSourceTest** | 7 | Tile source URL generation and attribution |
| **TileSourceTest** | 9 | Tile source URL generation, attribution and API keys |
| **TileTest** | 6 | Tile content equality, validation and toString |
| **UiSettingsTest** | 25 | UI settings (gestures, zoom controls, not-implemented features) |
| **UrlTileProviderTest** | 4 | Overlay tile downloading, HTTP 404 handling, shared HTTP client |
Expand Down
4 changes: 2 additions & 2 deletions examples/Example11MapTypes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ try {
| Carto Light | `MapType.CARTO_LIGHT` | CARTO | |
| Carto Dark | `MapType.CARTO_DARK` | CARTO | |
| Carto Voyager | `MapType.CARTO_VOYAGER` | CARTO | |
| Stamen Toner | `MapType.STAMEN_TONER` | Stadia Maps | |
| Stamen Watercolor | `MapType.STAMEN_WATERCOLOR` | Stadia Maps | |
| Stamen Toner | `MapType.STAMEN_TONER` | Stadia Maps | Stadia Maps |
| Stamen Watercolor | `MapType.STAMEN_WATERCOLOR` | Stadia Maps | Stadia Maps |

See the [Map Types Guide](../../docs/MAP_TYPES.md) for details on each type and on configuring API keys.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,19 +265,19 @@ fun MapTypeControls(
modifier = Modifier.fillMaxWidth(),
)

// Stamen Toner
// Stamen Toner (requires API key)
MapTypeButton(
text = "Stamen Toner",
description = "High-contrast black & white",
description = "Black & white (API key required)",
enabled = currentMapType != MapType.STAMEN_TONER,
onClick = { onMapTypeChange(MapType.STAMEN_TONER) },
modifier = Modifier.fillMaxWidth(),
)

// Stamen Watercolor
// Stamen Watercolor (requires API key)
MapTypeButton(
text = "Stamen Watercolor",
description = "Artistic watercolor rendering",
description = "Watercolor (API key required)",
enabled = currentMapType != MapType.STAMEN_WATERCOLOR,
onClick = { onMapTypeChange(MapType.STAMEN_WATERCOLOR) },
modifier = Modifier.fillMaxWidth(),
Expand All @@ -286,7 +286,7 @@ fun MapTypeControls(
// API Key Info
Text(
text = "API key required: Cycle Map, Transport, Transport Dark, " +
"Tracestrack Topo\n\nConfigure in AndroidManifest.xml\nSee docs/MAP_TYPES.md",
"Tracestrack Topo, Stamen Toner, Stamen Watercolor\n\nConfigure in AndroidManifest.xml\nSee docs/MAP_TYPES.md",
style = MaterialTheme.typography.bodySmall,
fontSize = 9.sp,
lineHeight = 11.sp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import java.util.concurrent.ConcurrentHashMap
/**
* Manages API keys for third-party tile providers.
*
* Some map types (CYCLEMAP, TRANSPORT, TRANSPORT_DARK, TRACESTRACK_TOPO) require API keys
* Some map types (CYCLEMAP, TRANSPORT, TRANSPORT_DARK, TRACESTRACK_TOPO, STAMEN_TONER,
* STAMEN_WATERCOLOR) and the Stamen overlays in [PredefinedTileProviders] require API keys
* from tile providers. Keys can be configured in two ways:
*
* **1. AndroidManifest.xml** (Recommended):
Expand All @@ -27,24 +28,30 @@ import java.util.concurrent.ConcurrentHashMap
* <meta-data
* android:name="de.afarber.openmapview.TRACESTRACK_API_KEY"
* android:value="your_tracestrack_key_here"/>
* <meta-data
* android:name="de.afarber.openmapview.STADIA_API_KEY"
* android:value="your_stadia_key_here"/>
* </application>
* ```
*
* **2. Programmatically** (Runtime):
* ```kotlin
* ApiKeyManager.setApiKey("thunderforest", "your_key_here")
* ApiKeyManager.setApiKey("tracestrack", "your_key_here")
* ApiKeyManager.setApiKey("stadia", "your_key_here")
* ```
*
* API keys set programmatically override keys from the manifest.
*
* ## Provider Names
* - `"thunderforest"` - For CYCLEMAP, TRANSPORT, and TRANSPORT_DARK map types
* - `"tracestrack"` - For TRACESTRACK_TOPO map type
* - `"stadia"` - For STAMEN_TONER, STAMEN_WATERCOLOR and the Stamen overlays
*
* ## Obtaining API Keys
* - **Thunderforest**: https://www.thunderforest.com/pricing/ (Free: 150k tiles/month)
* - **Tracestrack**: https://www.tracestrack.com/en/signup (Free tier available)
* - **Stadia Maps**: https://client.stadiamaps.com/signup/ (Free tier for non-commercial use)
*
* @see TileSource
* @see MapType
Expand All @@ -53,6 +60,7 @@ object ApiKeyManager {
private const val META_DATA_PREFIX = "de.afarber.openmapview."
private const val THUNDERFOREST_KEY_NAME = "THUNDERFOREST_API_KEY"
private const val TRACESTRACK_KEY_NAME = "TRACESTRACK_API_KEY"
private const val STADIA_KEY_NAME = "STADIA_API_KEY"

/**
* Thread-safe storage for API keys set programmatically.
Expand Down Expand Up @@ -105,7 +113,7 @@ object ApiKeyManager {
*
* Keys set this way override keys from AndroidManifest.xml.
*
* @param provider Provider name ("thunderforest" or "tracestrack")
* @param provider Provider name ("thunderforest", "tracestrack" or "stadia")
* @param key API key string
*/
@Synchronized
Expand All @@ -121,7 +129,7 @@ object ApiKeyManager {
*
* Checks programmatic keys first, then falls back to manifest meta-data.
*
* @param provider Provider name ("thunderforest" or "tracestrack")
* @param provider Provider name ("thunderforest", "tracestrack" or "stadia")
* @return API key string, or null if not configured
*/
@Synchronized
Expand All @@ -136,6 +144,7 @@ object ApiKeyManager {
when (normalizedProvider) {
"thunderforest" -> META_DATA_PREFIX + THUNDERFOREST_KEY_NAME
"tracestrack" -> META_DATA_PREFIX + TRACESTRACK_KEY_NAME
"stadia" -> META_DATA_PREFIX + STADIA_KEY_NAME
else -> null
}

Expand All @@ -145,7 +154,7 @@ object ApiKeyManager {
/**
* Checks if an API key is configured for the given provider.
*
* @param provider Provider name ("thunderforest" or "tracestrack")
* @param provider Provider name ("thunderforest", "tracestrack" or "stadia")
* @return true if a key is available, false otherwise
*/
fun hasApiKey(provider: String): Boolean = !getApiKey(provider).isNullOrEmpty()
Expand Down
Loading
Loading