Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prototype custom location provider and multiple location component instances. #1476

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
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
27 changes: 27 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,33 @@
android:name="android.support.PARENT_ACTIVITY"
android:value=".ExampleOverviewActivity" />
</activity>

<activity
android:name=".examples.location.CustomJourneyLocationProviderActivity"
android:description="@string/description_custom_location_provider"
android:exported="true"
android:label="@string/activity_custom_location_provider">
<meta-data
android:name="@string/category"
android:value="@string/category_location" />
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ExampleOverviewActivity" />
</activity>

<activity
android:name=".examples.location.MultipleLocationComponentActivity"
android:description="@string/description_multiple_location_component"
android:exported="true"
android:label="@string/activity_multiple_location_component">
<meta-data
android:name="@string/category"
android:value="@string/category_location" />
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ExampleOverviewActivity" />
</activity>

<activity
android:name=".TestMapActivity"
android:exported="true" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package com.mapbox.maps.testapp.examples.location

import android.annotation.SuppressLint
import android.os.Bundle
import android.view.ViewGroup
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import com.mapbox.geojson.Point
import com.mapbox.maps.CameraOptions
import com.mapbox.maps.MapView
import com.mapbox.maps.Style
import com.mapbox.maps.plugin.LocationPuck3D
import com.mapbox.maps.plugin.annotation.annotations
import com.mapbox.maps.plugin.annotation.generated.PointAnnotation
import com.mapbox.maps.plugin.annotation.generated.PointAnnotationManager
import com.mapbox.maps.plugin.annotation.generated.PointAnnotationOptions
import com.mapbox.maps.plugin.annotation.generated.createPointAnnotationManager
import com.mapbox.maps.plugin.gestures.OnMapClickListener
import com.mapbox.maps.plugin.gestures.gestures
import com.mapbox.maps.plugin.locationcomponent.CustomJourneyLocationProvider
import com.mapbox.maps.plugin.locationcomponent.Journey
import com.mapbox.maps.plugin.locationcomponent.location2
import com.mapbox.maps.testapp.R
import com.mapbox.maps.testapp.utils.BitmapUtils
import java.util.*

/**
* Example of using custom location provider.
*/
class CustomJourneyLocationProviderActivity : AppCompatActivity(), OnMapClickListener {
private val journey = Journey()
private val customJourneyLocationProvider = CustomJourneyLocationProvider().apply { loadJourney(journey) }
private lateinit var mapView: MapView
private val annotationList = LinkedList<PointAnnotation>()
private lateinit var pointAnnotationManager: PointAnnotationManager

@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mapView = MapView(this)
setContentView(mapView)
mapView.addView(
Button(this).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
text = "Cancel"
setOnClickListener {
journey.pause()
}
}
)
pointAnnotationManager = mapView.annotations.createPointAnnotationManager()
mapView.getMapboxMap()
.apply {
setCamera(
CameraOptions.Builder()
.center(HELSINKI)
.pitch(40.0)
.zoom(14.0)
.build()
)
loadStyleUri(Style.MAPBOX_STREETS) {
initLocationComponent()
initClickListeners()
journey.start()
}
}

journey.observeJourneyUpdates { location, bearing, locationAnimationDurationMs, bearingAnimateDurationMs ->
annotationList.poll()?.let {
pointAnnotationManager.delete(it)
}
true
}
}

private fun initClickListeners() {
mapView.gestures.addOnMapClickListener(this)
}

private fun initLocationComponent() {
val locationComponentPlugin2 = mapView.location2
locationComponentPlugin2.setLocationProvider(customJourneyLocationProvider)
locationComponentPlugin2.let {
it.locationPuck = LocationPuck3D(
modelUri = "asset://sportcar.glb",
modelScale = listOf(0.2f, 0.2f, 0.2f),
modelTranslation = listOf(0.1f, 0.1f, 0.1f),
modelRotation = listOf(0.0f, 0.0f, 180.0f)
)
}
locationComponentPlugin2.enabled = true
locationComponentPlugin2.puckBearingEnabled = true
}

override fun onMapClick(point: Point): Boolean {
journey.queueLocationUpdate(point)
BitmapUtils.bitmapFromDrawableRes(
this,
R.drawable.red_marker
)?.let {
pointAnnotationManager.create(
PointAnnotationOptions()
.withPoint(point)
.withIconImage(it)
.withDraggable(true)
).also { annotation -> annotationList.add(annotation) }
}
return true
}

companion object {
private val HELSINKI = Point.fromLngLat(24.9384, 60.1699)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package com.mapbox.maps.testapp.examples.location

import android.annotation.SuppressLint
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.mapbox.geojson.Point
import com.mapbox.maps.*
import com.mapbox.maps.plugin.LocationPuck2D
import com.mapbox.maps.plugin.LocationPuck3D
import com.mapbox.maps.plugin.annotation.annotations
import com.mapbox.maps.plugin.annotation.generated.*
import com.mapbox.maps.plugin.gestures.OnMapClickListener
import com.mapbox.maps.plugin.gestures.gestures
import com.mapbox.maps.plugin.locationcomponent.CustomJourneyLocationProvider
import com.mapbox.maps.plugin.locationcomponent.Journey
import com.mapbox.maps.plugin.locationcomponent.LocationComponentInitOptions
import com.mapbox.maps.plugin.locationcomponent.LocationComponentPlugin2
import com.mapbox.maps.plugin.viewport.data.MultiPuckViewportStateBearing
import com.mapbox.maps.plugin.viewport.data.MultiPuckViewportStateOptions
import com.mapbox.maps.plugin.viewport.state.MultiPuckViewportState
import com.mapbox.maps.plugin.viewport.viewport
import com.mapbox.maps.testapp.R
import com.mapbox.maps.testapp.databinding.ActivityMultiLocationcomponentBinding
import com.mapbox.maps.testapp.utils.BitmapUtils
import com.mapbox.maps.testapp.utils.createLocationComponent
import java.util.*

/**
* Example of using multiple location component.
*/
@OptIn(MapboxExperimental::class)
class MultipleLocationComponentActivity : AppCompatActivity(), OnMapClickListener {
private lateinit var mapView: MapView
private val journeys = mutableListOf(Journey(speed = 150.0, angularSpeed = 150.0), Journey(speed = 100.0, angularSpeed = 150.0))
private val customJourneyLocationProviders = mutableListOf(
CustomJourneyLocationProvider().apply { loadJourney(journeys.first()) },
CustomJourneyLocationProvider().apply { loadJourney(journeys.last()) }
)
private val annotationLists =
mutableListOf(LinkedList<PointAnnotation>(), LinkedList<PointAnnotation>())
private val locationComponents = mutableListOf<LocationComponentPlugin2>()
private lateinit var pointAnnotationManager: PointAnnotationManager
private lateinit var multiPuckViewportState: MultiPuckViewportState

var selectedPuck = 0

@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMultiLocationcomponentBinding.inflate(layoutInflater)
setContentView(binding.root)
mapView = binding.mapView
binding.toggleControlBtn.apply {
text = "Controlling ${if (selectedPuck == 0) "Car" else "Duck"}"
setOnClickListener {
toggleControl()
text = "Controlling ${if (selectedPuck == 0) "Car" else "Duck"}"
}
}
binding.followPucksButton.setOnClickListener {
mapView.viewport.transitionTo(multiPuckViewportState)
}
pointAnnotationManager = mapView.annotations.createPointAnnotationManager()
mapView.getMapboxMap()
.apply {
setCamera(
CameraOptions.Builder()
.center(HELSINKI)
.pitch(40.0)
.zoom(14.0)
.build()
)
loadStyleUri(Style.MAPBOX_STREETS) {
initLocationComponents()
initClickListeners()
journeys.forEach { it.start() }
}
}

journeys.forEachIndexed { index, journey ->
journey.observeJourneyUpdates { _, _, _, _ ->
annotationLists[index].poll()?.let {
pointAnnotationManager.delete(it)
}
true
}
}
}

private fun toggleControl() {
selectedPuck = (selectedPuck + 1) % 2
}

private fun initClickListeners() {
mapView.gestures.addOnMapClickListener(this)
}

private fun initLocationComponents() {
// Puck with pulsing car
locationComponents.add(
mapView.createLocationComponent(LocationComponentInitOptions.getNextUniqueLocationComponentOptions())
.apply {
setLocationProvider(customJourneyLocationProviders.first())
enabled = true
locationPuck = LocationPuck2D(
topImage = null,
bearingImage = null,
)
puckBearingEnabled = true
pulsingEnabled = true
}
)
locationComponents.add(
mapView.createLocationComponent(LocationComponentInitOptions.getNextUniqueLocationComponentOptions())
.apply {
setLocationProvider(customJourneyLocationProviders.first())
enabled = true
locationPuck = LocationPuck3D(
modelUri = "asset://sportcar.glb",
modelScale = listOf(0.3f, 0.3f, 0.3f),
modelTranslation = listOf(0.1f, 0.1f, 0.1f),
modelRotation = listOf(0.0f, 0.0f, 180.0f)
)
puckBearingEnabled = true
}
)
// Puck with pulsing duck
locationComponents.add(
mapView.createLocationComponent(LocationComponentInitOptions.getNextUniqueLocationComponentOptions())
.apply {
setLocationProvider(customJourneyLocationProviders.last())
enabled = true
locationPuck = LocationPuck2D(
topImage = null,
bearingImage = null,
)
puckBearingEnabled = true
pulsingEnabled = true
}
)
locationComponents.add(
mapView.createLocationComponent(LocationComponentInitOptions.getNextUniqueLocationComponentOptions())
.apply {
setLocationProvider(customJourneyLocationProviders.last())
enabled = true
locationPuck = LocationPuck3D(
modelUri = "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/Duck/glTF-Embedded/Duck.gltf",
modelScale = listOf(0.5f, 0.5f, 0.5f),
modelRotation = listOf(0f, 0f, -90f),
modelTranslation = listOf(0f, 0.0f, 0.0f)
)
puckBearingEnabled = true
}
)
multiPuckViewportState = mapView.viewport.makeMultiPuckViewportState(
MultiPuckViewportStateOptions
.Builder()
.bearing(MultiPuckViewportStateBearing.SyncWithLocationPuck(locationComponents.first()))
.padding(EdgeInsets(100.0, 100.0, 100.0, 100.0))
.build(),
locationComponents = locationComponents
)
}

override fun onMapClick(point: Point): Boolean {
journeys[selectedPuck].queueLocationUpdate(point)
BitmapUtils.bitmapFromDrawableRes(
this,
if (selectedPuck == 0) R.drawable.red_marker else R.drawable.blue_marker_view
)?.let {
pointAnnotationManager.create(
PointAnnotationOptions()
.withPoint(point)
.withIconImage(it)
.withDraggable(true)
).also { annotation -> annotationLists[selectedPuck].add(annotation) }
}
return true
}

companion object {
private val HELSINKI = Point.fromLngLat(24.9384, 60.1699)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.mapbox.maps.testapp.utils

import com.mapbox.maps.MapView
import com.mapbox.maps.plugin.Plugin
import com.mapbox.maps.plugin.locationcomponent.LocationComponentInitOptions
import com.mapbox.maps.plugin.locationcomponent.LocationComponentPlugin2
import com.mapbox.maps.plugin.locationcomponent.LocationComponentPluginImpl

public fun MapView.createLocationComponent(locationComponentInitOptions: LocationComponentInitOptions): LocationComponentPlugin2 {
val locationComponent = LocationComponentPluginImpl(locationComponentInitOptions)
val locationComponentPlugin = Plugin.Custom(
locationComponentInitOptions.hashCode().toString(),
locationComponent
)
this.createPlugin(locationComponentPlugin)
return locationComponent
}
36 changes: 36 additions & 0 deletions app/src/main/res/layout/activity_multi_locationcomponent.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".examples.MultiDisplayActivity">

<com.mapbox.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:orientation="vertical"
android:gravity="center"
android:layout_marginBottom="10dp">

<Button
android:id="@+id/toggleControlBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:text="" />

<Button
android:id="@+id/followPucksButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/move_camera" />

</LinearLayout>
</RelativeLayout>
Loading