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
25 changes: 6 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,9 @@ dependencies {

The library is available on [Maven Central](https://central.sonatype.com/artifact/de.afarber/openmapview). Alternative distribution via [JitPack](https://jitpack.io/#afarber/OpenMapView) is also supported.

## License Compliance
## License

OpenMapView is licensed under the **MIT License** - use freely in commercial apps.

**Dependency Licenses:**
- All runtime dependencies use Apache 2.0 or MIT licenses (business-friendly)
- View complete [Dependency License Report](https://afarber.github.io/OpenMapView/licenses/)
- No GPL or restrictive copyleft licenses

**Dependencies (5 total):**
- androidx.core:core-ktx (Apache 2.0)
- androidx.lifecycle:lifecycle-runtime-ktx (Apache 2.0)
- androidx.compose.ui:ui-graphics (Apache 2.0)
- io.ktor:ktor-client-android (Apache 2.0)
- com.jakewharton:disklrucache (Apache 2.0)
OpenMapView is MIT licensed, so you can use it in commercial apps. Its five runtime dependencies (androidx core-ktx, lifecycle-runtime-ktx, Compose ui-graphics, ktor-client-android and DiskLruCache) are all Apache 2.0. See the [Dependency License Report](https://afarber.github.io/OpenMapView/licenses/) for details.

## Features

Expand All @@ -49,13 +37,12 @@ OpenMapView is licensed under the **MIT License** - use freely in commercial app
- External app integration (open in Google Maps, OsmAnd, etc. via geo: URI)
- GeoJSON import support
- Extensible marker, overlay, and gesture handling
- MIT licensed (use freely in commercial apps)

## API Documentation

Full API reference documentation is available at [afarber.github.io/OpenMapView](https://afarber.github.io/OpenMapView/).

The documentation is automatically generated from KDoc comments and updated with every commit to main.
The documentation is generated from KDoc comments and redeployed whenever the library sources change on main.

## Examples

Expand All @@ -71,7 +58,7 @@ Explore the example applications to see OpenMapView in action:
- [Example08Circles](examples/Example08Circles) - Circles with radius, styling, z-index ordering, and click listeners
- [Example09Overlays](examples/Example09Overlays) - Tile overlays with transparency control (OpenSeaMap, Railways, Trails, Snow)
- [Example10GroundOverlays](examples/Example10GroundOverlays) - Ground overlays with position/bounds modes, rotation, and transparency
- [Example11MapTypes](examples/Example11MapTypes) - Switching between 5 map types (Normal, Terrain, Humanitarian, Cycle, None)
- [Example11MapTypes](examples/Example11MapTypes) - Switching between all 15 map types (OSM, CyclOSM, Thunderforest, CARTO, Stamen and more)
- [Example12Toolbar](examples/Example12Toolbar) - Open location in external map apps via geo: URI with OpenStreetMap browser fallback

![Example01Pan Demo](examples/Example01Pan/screenshot.gif)
Expand Down Expand Up @@ -107,7 +94,7 @@ fun MapViewScreen() {
lifecycleOwner.lifecycle.addObserver(this)

setCenter(LatLng(51.4661, 7.2491))
setZoom(14.0)
setZoom(14.0f)

// Add markers - Kotlin style (direct instantiation)
addMarker(Marker(
Expand Down Expand Up @@ -138,7 +125,7 @@ class MainActivity : AppCompatActivity() {
setContentView(R.layout.activity_main)

val mapView = findViewById<OpenMapView>(R.id.mapView)
mapView.setZoom(14.0)
mapView.setZoom(14.0f)
mapView.setCenter(LatLng(51.4661, 7.2491))
}
}
Expand Down
2 changes: 1 addition & 1 deletion docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ All contributions must meet the following requirements before being merged:

### 1. Code Formatting

All Kotlin code must follow the project's formatting rules enforced by Spotless with ktlint 1.3.1.
All Kotlin code must follow the project's formatting rules enforced by Spotless with ktlint (versions in `gradle/libs.versions.toml`).

**Before committing**, run:

Expand Down
25 changes: 11 additions & 14 deletions docs/GITHUB_WORKFLOWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,10 @@ instrumented-test (Phone + Automotive) runs in parallel
7. **build-library** - Builds library AAR (depends on all above, runs in parallel with build-examples)
8. **build-examples** - Builds example APKs (depends on all above, runs in parallel with build-library)
9. **instrumented-test** - Runs instrumentation tests on phone and automotive emulators (PR only)
10. **instrumented-test-status** - Reports one combined "Instrumentation Tests" check for the device matrix, used by branch protection (PR only)

**Total Duration**:
- **Maintainer pushes to main**: ~3-4 minutes (no instrumentation tests)
- **Pushes to main** (merged PRs and release commits): ~3-4 minutes (no instrumentation tests)
- **Pull Requests**: ~10-15 minutes (includes instrumentation tests on phone + automotive)

**Benefits**:
Expand Down Expand Up @@ -157,7 +158,7 @@ lint ──────┘ │ ├──→ publish
- Validates tag format (must be `vMAJOR.MINOR.PATCH`)
- Extracts version number (e.g., `v0.2.0` -> `0.2.0`)
- Signs artifacts with GPG key
- Uploads to Maven Central OSSRH
- Uploads the bundle to the Maven Central Portal, which publishes it automatically
- Generates changelog from git history
- Creates GitHub Release with:
- Version number and changelog
Expand Down Expand Up @@ -268,14 +269,14 @@ For the release workflow to function, the project owner must configure these sec
**Location**: Settings -> Secrets and variables -> Actions -> Repository secrets

### 1. OSSRH_USERNAME
- **Description**: Sonatype JIRA username
- **Used for**: Authenticating to Maven Central OSSRH
- **How to get**: Created when registering at https://issues.sonatype.org
- **Description**: Username part of a Central Portal user token (the secret keeps its old name)
- **Used for**: Authenticating to the Maven Central Portal
- **How to get**: Generate a user token at https://central.sonatype.com/account

### 2. OSSRH_PASSWORD
- **Description**: Sonatype JIRA password
- **Used for**: Authenticating to Maven Central OSSRH
- **How to get**: Set when registering at https://issues.sonatype.org
- **Description**: Password part of the same Central Portal user token
- **Used for**: Authenticating to the Maven Central Portal
- **How to get**: Shown together with the username when the token is generated

### 3. SIGNING_KEY
- **Description**: Base64-encoded GPG private key
Expand Down Expand Up @@ -349,11 +350,7 @@ git pull
# 3. Watch the workflow
# Go to: https://github.com/afarber/OpenMapView/actions

# 4. For first release only: manually release staging repository
# Log in to: https://s01.oss.sonatype.org/
# Find your staging repo, click "Close", then "Release"

# 5. Verify publication after 2-4 hours
# 4. Verify publication, usually after 10-30 minutes
# https://central.sonatype.com/artifact/de.afarber/openmapview
```

Expand Down Expand Up @@ -445,7 +442,7 @@ publish job:
- Create GitHub Release - PASS
|
v
Wait 2-4 hours -> Library available on Maven Central
Wait 10-30 minutes -> Library available on Maven Central
```

## Benefits of This Architecture
Expand Down
2 changes: 1 addition & 1 deletion docs/LIFECYCLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ fun MapViewScreen() {
lifecycleOwner.lifecycle.addObserver(this)

setCenter(LatLng(51.4661, 7.2491))
setZoom(14.0)
setZoom(14.0f)
}
}
)
Expand Down
4 changes: 2 additions & 2 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. Twelve types work without any configuration, while three premium types require free API keys.
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.

```kotlin
val mapView = OpenMapView(context)
Expand Down Expand Up @@ -401,7 +401,7 @@ See the **Example11MapTypes** sample app for a complete demonstration of all map
val mapView = OpenMapView(context)
lifecycle.addObserver(mapView)
mapView.setCenter(LatLng(46.8182, 8.2275))
mapView.setZoom(12.0)
mapView.setZoom(12.0f)
mapView.setMapType(MapType.CYCLOSM) // Switch map types dynamically
```

Expand Down
36 changes: 5 additions & 31 deletions docs/PERFORMANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ Map tiles are decoded using the `RGB_565` bitmap configuration instead of the de
val options = BitmapFactory.Options().apply {
inPreferredConfig = Bitmap.Config.RGB_565
inScaled = false
inDither = false
inPreferQualityOverSpeed = false
}
```

Expand Down Expand Up @@ -322,14 +320,6 @@ Typical memory footprint for a visible viewport at zoom level 10:
- **Total active memory:** ~4MB for tiles
- **Memory cache capacity:** ~32-64MB depending on device

### Cache Hit Rates

Expected cache hit rates with typical usage:

- **Memory cache:** 80-90% for panning within same area
- **Disk cache:** 60-70% on app restart
- **Network downloads:** 10-20% for new areas

### Network Usage

With prefetching enabled:
Expand All @@ -338,36 +328,20 @@ With prefetching enabled:
- **Pan gesture:** 0-4 tile downloads (~0-150KB) from cache
- **Zoom change:** 0-20 tile downloads (~0-700KB) depending on zoom delta


## Benchmarking

To measure performance in your app:
The tile caches are internal, so measure from the outside:

```kotlin
// Memory usage
val memoryInfo = ActivityManager.MemoryInfo()
activityManager.getMemoryInfo(memoryInfo)

// Cache statistics
val cacheSize = tileCache.size()
val cacheHits = tileCache.hitCount()
val cacheMisses = tileCache.missCount()

// Rendering performance
Choreographer.getInstance().postFrameCallback { frameTimeNanos ->
// Measure frame time
}
```
- **Memory:** Android Studio Memory Profiler, or `adb shell dumpsys meminfo <your.package>`
- **Network:** Android Studio Network Inspector shows every tile request and whether panning hits the cache
- **Rendering:** Profile GPU Rendering in the developer options, or a `Choreographer.FrameCallback`

## Best Practices

For optimal performance:

1. **Lifecycle integration:** Register OpenMapView with lifecycle observer (see [Lifecycle Management](LIFECYCLE.md))
2. **Memory limits:** Monitor memory usage if displaying multiple maps simultaneously
3. **Cache clearing:** Provide UI to clear cache if storage becomes an issue
4. **Network awareness:** Consider pausing downloads on metered connections
5. **Error handling:** Handle network failures gracefully
2. **Several maps at once:** Each OpenMapView has its own memory cache of up to 1/8 of the heap, so watch memory usage when showing more than one

## References

Expand Down
6 changes: 3 additions & 3 deletions docs/PUBLIC_API.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,9 @@ These properties apply to:
| Method | Return Type | Notes |
| ------------------------------ | ----------- | ---------------------------------------------------------------- |
| `setCenter(LatLng)` | `void` | Direct method on OpenMapView (not via separate GoogleMap object) |
| `setZoom(double)` | `void` | Direct method on OpenMapView (not via separate GoogleMap object) |
| `getZoom()` | `double` | Direct method on OpenMapView (not via separate GoogleMap object) |
| `setMapType(int)` | `void` | Supports NORMAL, TERRAIN, HUMANITARIAN, CYCLE, NONE |
| `setZoom(float)` | `void` | Direct method on OpenMapView (not via separate GoogleMap object) |
| `getZoom()` | `float` | Direct method on OpenMapView (not via separate GoogleMap object) |
| `setMapType(int)` | `void` | Supports all 15 `MapType` constants, see MAP_TYPES.md |
| `getMapType()` | `int` | |
| `setMapStyle(MapStyleOptions)` | `boolean` | Not implemented |

Expand Down
13 changes: 6 additions & 7 deletions docs/PUBLISHING.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,8 @@ Examples:

When creating a new release:

- [ ] Ensure all tests pass: `./gradlew test`
- [ ] Run code formatting: `./gradlew spotlessApply`
- [ ] Verify local build: `./gradlew build`
- [ ] Test Maven publication: `./gradlew publishToMavenLocal`
- [ ] Create and push version tag (e.g., `v0.3.0`)
- [ ] Make sure CI on main is green and your local main is up to date
- [ ] Run `./scripts/publish-release.sh` (next patch version) or `./scripts/publish-release.sh vX.Y.Z`. It bumps the version in the docs, commits, creates a signed tag and pushes main and the tag
- [ ] Monitor GitHub Actions release workflow
- [ ] Verify Maven Central publication (10-30 minutes)
- [ ] Verify JitPack build status
Expand Down Expand Up @@ -360,13 +357,15 @@ git push origin v0.3.0

## Installation Examples

Replace `<version>` with the latest release shown in the [README](../README.md#installation).

### Maven Central

No repository configuration required:

```kotlin
dependencies {
implementation("de.afarber:openmapview:0.1.0")
implementation("de.afarber:openmapview:<version>")
}
```

Expand All @@ -386,6 +385,6 @@ dependencyResolutionManagement {

```kotlin
dependencies {
implementation("com.github.afarber:OpenMapView:0.1.0")
implementation("com.github.afarber:OpenMapView:<version>")
}
```
18 changes: 11 additions & 7 deletions docs/TESTING_INSTRUMENTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ Test results and reports are uploaded as separate artifacts for each device with

```
openmapview/src/androidTest/kotlin/de/afarber/openmapview/
├── MapControllerInstrumentationTest.kt # Canvas rendering and markers (7 tests)
├── TileDownloaderInstrumentationTest.kt # Real OSM tile downloads (2 tests)
└── MapControllerInstrumentationTest.kt # Canvas rendering and markers (7 tests)
├── TouchGestureInstrumentationTest.kt # Click vs. drag detection (2 tests)
└── UiSettingsInstrumentationTest.kt # Enabling and disabling gestures (4 tests)
```

## Dependencies
Expand All @@ -91,15 +93,17 @@ Instrumented testing dependencies in `openmapview/build.gradle.kts`:

```kotlin
dependencies {
androidTestImplementation("androidx.test:core-ktx:1.7.0")
androidTestImplementation("androidx.test:runner:1.7.0")
androidTestImplementation("androidx.test:rules:1.7.0")
androidTestImplementation("androidx.test.ext:junit-ktx:1.3.0")
androidTestImplementation("junit:junit:4.13.2")
androidTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.11.0")
androidTestImplementation(libs.androidx.test.core.ktx)
androidTestImplementation(libs.androidx.test.runner)
androidTestImplementation(libs.androidx.test.rules)
androidTestImplementation(libs.androidx.test.junit.ktx)
androidTestImplementation(libs.junit)
androidTestImplementation(libs.kotlinx.coroutines.test)
}
```

The versions are in `gradle/libs.versions.toml`.

## References

- [Android Testing Documentation](https://developer.android.com/training/testing/instrumented-tests)
Expand Down
20 changes: 11 additions & 9 deletions docs/TESTING_UNIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ openmapview/src/test/kotlin/de/afarber/openmapview/

## Test Framework Stack

| Component | Version | Purpose |
|-----------|---------|---------|
| **JUnit** | 4.13.2 | Test runner and assertions |
| **Kotlin Test** | (inherited) | Kotlin-specific test utilities |
| **MockK** | 1.14.11 | Mocking framework for Kotlin |
| **Robolectric** | 4.17 | Android framework shadow implementations |
| **Ktor Client Mock** | 3.6.0 | HTTP client mocking for network tests |
| **Coroutines Test** | 1.11.0 | Testing coroutines and async code |
| Component | Purpose |
|-----------|---------|
| **JUnit 4** | Test runner and assertions |
| **Kotlin Test** | Kotlin-specific test utilities |
| **MockK** | Mocking framework for Kotlin |
| **Robolectric** | Android framework shadow implementations |
| **Ktor Client Mock** | HTTP client mocking for network tests |
| **Coroutines Test** | Testing coroutines and async code |

The versions are in `gradle/libs.versions.toml` and kept up to date by Dependabot.

## Running Tests

Expand Down Expand Up @@ -174,7 +176,7 @@ android {
}

dependencies {
testImplementation("org.robolectric:robolectric:4.14")
testImplementation(libs.robolectric)
}
```

Expand Down
Loading
Loading