diff options
Diffstat (limited to 'mapbox/src/main/java/com')
20 files changed, 1658 insertions, 0 deletions
diff --git a/mapbox/src/main/java/com/example/mapbox/MainActivity.kt b/mapbox/src/main/java/com/example/mapbox/MainActivity.kt new file mode 100644 index 0000000000..90e76a1f48 --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/MainActivity.kt @@ -0,0 +1,153 @@ +package com.example.mapbox + +import android.annotation.SuppressLint +import android.location.Location +import android.os.Bundle +import android.os.SystemClock +import android.support.constraint.ConstraintLayout +import android.support.wearable.activity.WearableActivity +import android.util.Log +import android.widget.Toast +import androidx.lifecycle.Observer +import com.example.mapbox.ui.MapboxMapView +import com.example.mapbox.ui.extensions.addViewAndMatchItToParent +import com.mapbox.android.core.permissions.PermissionsListener +import com.mapbox.android.core.permissions.PermissionsManager +import com.mapbox.mapboxsdk.Mapbox +import com.mapbox.mapboxsdk.maps.MapboxMap +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback +import com.mapbox.mapboxsdk.testapp.R +import com.soy.android.maps.compass.WassCompassEngine +import com.soy.android.maps.livedata.MapViewSensors +import dagger.android.AndroidInjection +import javax.inject.Inject + +class MainActivity : WearableActivity(), PermissionsListener, OnMapReadyCallback { + override fun onMapReady(mapboxMap: MapboxMap) { + measureAndPrintTimeMillis("onStart.requestSensorUpdates") { + requestSensorUpdates() + } + mapboxMapView.onMapReady(mapboxMap) + } + + private lateinit var mapboxMapView: MapboxMapView + + @Inject + lateinit var sensors: MapViewSensors + + @SuppressLint("MissingPermission") + override fun onCreate(savedInstanceState: Bundle?) { + AndroidInjection.inject(this) + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + if (PermissionsManager.areLocationPermissionsGranted(this)) { + createMapboxMapView() + } else { + PermissionsManager(this).requestLocationPermissions(this) + } + setAmbientEnabled() + } + + private fun createMapboxMapView() { + Mapbox.getInstance(this, getString(R.string.mapbox_api_key)) + val location = sensors.locationLiveData.value + val root = findViewById<ConstraintLayout>(R.id.content) + mapboxMapView = MapboxMapView(this, location).apply { + compassEngine = WassCompassEngine(sensors.headingLiveData) + root.addViewAndMatchItToParent(this) + onCreate(null) + getMapAsync(this@MainActivity) + } + } + + public override fun onResume() { + super.onResume() + measureAndPrintTimeMillis("onResume") { + mapboxMapView.onResume() + } + } + + public override fun onPause() { + super.onPause() + measureAndPrintTimeMillis("onPause") { + mapboxMapView.onPause() + } + } + + override fun onLowMemory() { + super.onLowMemory() + measureAndPrintTimeMillis("onLowMemory") { + mapboxMapView.onLowMemory() + } + } + + override fun onStart() { + super.onStart() + measureAndPrintTimeMillis("onStart.mapOnStart") { + mapboxMapView.onStart() + } + } + + override fun onStop() { + super.onStop() + removeSensorUpdates() + measureAndPrintTimeMillis("onStop") { + mapboxMapView.onStop() + } + } + + override fun onDestroy() { + super.onDestroy() + measureAndPrintTimeMillis("onDestroy") { + mapboxMapView.onDestroy() + } + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + measureAndPrintTimeMillis("onSaveInstanceState") { + mapboxMapView.onSaveInstanceState(outState) + } + } + + private fun requestSensorUpdates() { + sensors.requestUpdates(locationObserver) + mapboxMapView.compassEngine?.requestUpdates() + } + + private fun removeSensorUpdates() { + sensors.removeUpdates(locationObserver) + mapboxMapView.compassEngine?.removeUpdates() + } + + // Sensors + private val locationObserver: Observer<Location> = Observer { location -> + measureAndPrintTimeMillis("onNewLocation") { + mapboxMapView.onNewLocation(location) + } + } + + override fun onExplanationNeeded(permissionsToExplain: MutableList<String>?) { + Toast.makeText(this, R.string.user_location_permission_explanation, Toast.LENGTH_LONG).show() + } + + override fun onPermissionResult(granted: Boolean) { + if (granted) { + createMapboxMapView() + } else { + Toast.makeText(this, R.string.user_location_permission_not_granted, Toast.LENGTH_LONG).show() + } + } +} + +/** + * Executes the given [block] and returns elapsed time in milliseconds. + */ +public inline fun <T> measureAndPrintTimeMillis(blockName: String, block: () -> T): T { + val start = SystemClock.elapsedRealtime() + val t = block() + val elapsedTime = SystemClock.elapsedRealtime() - start + Log.d("MapExample", "It took $elapsedTime ms to run [$blockName]") + return t +} + diff --git a/mapbox/src/main/java/com/example/mapbox/MainActivityModule.kt b/mapbox/src/main/java/com/example/mapbox/MainActivityModule.kt new file mode 100644 index 0000000000..eec66ebee3 --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/MainActivityModule.kt @@ -0,0 +1,10 @@ +package com.example.mapbox + +import dagger.Module +import dagger.android.ContributesAndroidInjector + +@Module +abstract class MainActivityModule { + @ContributesAndroidInjector + internal abstract fun mainActivity(): MainActivity +} diff --git a/mapbox/src/main/java/com/example/mapbox/MapboxApp.kt b/mapbox/src/main/java/com/example/mapbox/MapboxApp.kt new file mode 100644 index 0000000000..ded4931802 --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/MapboxApp.kt @@ -0,0 +1,16 @@ +package com.example.mapbox + +import dagger.android.AndroidInjector +import dagger.android.DaggerApplication + +class MapboxApp : DaggerApplication() { + private val appComponent: AndroidInjector<MapboxApp> by lazy { + DaggerAppComponent + .builder() + .create(this) + } + + override fun applicationInjector(): AndroidInjector<out DaggerApplication> { + return appComponent + } +}
\ No newline at end of file diff --git a/mapbox/src/main/java/com/example/mapbox/breadcrumb/Breadcrumb.kt b/mapbox/src/main/java/com/example/mapbox/breadcrumb/Breadcrumb.kt new file mode 100644 index 0000000000..af27cc36b6 --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/breadcrumb/Breadcrumb.kt @@ -0,0 +1,157 @@ +package com.soy.android.maps.breadcrumb + +import android.content.res.Resources +import com.example.mapbox.breadcrumb.ExerciseEngineState +import com.example.mapbox.ui.MapboxMapView +import com.mapbox.mapboxsdk.geometry.LatLng +import com.mapbox.mapboxsdk.location.OnLocationStaleListener +import com.mapbox.mapboxsdk.maps.MapboxMap +import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.plugins.annotation.Line +import com.mapbox.mapboxsdk.plugins.annotation.LineManager +import com.mapbox.mapboxsdk.plugins.annotation.SymbolManager +import timber.log.Timber + +/** + * Note that this is not public API and taken from [com.mapbox.mapboxsdk.location.LocationComponentConstants]. Needed + * to be hardcoded to have the line layer below the location indicator + */ +private const val LOCATION_INDICATOR_BACKGROUND_LAYER_ID = "mapbox-location-stroke-layer" + +class Breadcrumb( + mapView: MapboxMapView, + private val map: MapboxMap, + style: Style +) : OnLocationStaleListener { + + private val lineManager: LineManager = LineManager(mapView, map, style, LOCATION_INDICATOR_BACKGROUND_LAYER_ID) + private val symbolManager: SymbolManager = SymbolManager(mapView, map, style, LOCATION_INDICATOR_BACKGROUND_LAYER_ID) + private val resources: Resources + + init { + map.locationComponent.addOnLocationStaleListener(this) + resources = mapView.resources + } + + /** + * Flag that represents whether start symbol is created + */ + private var startSymbolCreated = false + + /** + * Holds [LatLng] list of current recording state line. A recording state line is the line which holds the list of + * [LatLng] recorded during [Recording] state. When state is [Paused] last recording state line does not receive + * updates and when the state is [Recording] after [Paused] state a new line is created and that line is updated + * according to [currentRecordingStateLatLngs] + */ + private var currentRecordingStateLatLngs = mutableListOf<LatLng>() + + /** + * A recording state line is the line which is created and updated during [Recording] state. + * + * When state is [Paused] last recording state line does not receive updates. + * + * [currentRecordingStateLine] is the line which is created either at the beginning of the exercise or when the + * state is [Recording] again after last [Paused] state. + */ + private var currentRecordingStateLine: Line? = null + + /** + * The [ExerciseEngineState] which belongs to the previous [com.soy.android.maps.livedata.StatefulLocation] + */ + private var previousExerciseEngineState: ExerciseEngineState? = null + + private var fromStaleState = false + + private var isMapViewVisible = true + + internal fun onNewLocation(latLng: LatLng, exerciseEngineState: ExerciseEngineState?) { + if (!startSymbolCreated) { + // We create a start symbol when the exercise is started + symbolManager.addStartExerciseSymbol(latLng) + startSymbolCreated = true + previousExerciseEngineState = exerciseEngineState + return + } + when { + exerciseRecording(exerciseEngineState) -> { + if (fromStaleState) { + fromStaleState = false + map.locationComponent.addOnLocationStaleListener(this) + lineManager.createStaleStateLine(listOf(currentRecordingStateLatLngs.last(), latLng)) + // clear the recording state latlng list and add the start point for the new line + currentRecordingStateLatLngs.clear() + currentRecordingStateLatLngs.add(latLng) + } else { + currentRecordingStateLatLngs.add(latLng) + createOrUpdateRecordingLine() + } + } + exercisePaused(exerciseEngineState) -> { + // add the end point for currentRecordingStateLine + currentRecordingStateLatLngs.add(latLng) + createOrUpdateRecordingLine() + // add the start point of the pause line + } + exerciseResumed(exerciseEngineState) -> { + // add the end point of the pause line + // create the pause line + lineManager.createPausedStateLine(listOf(currentRecordingStateLatLngs.last(), latLng)) + Timber.d("Pause state line is created") + // after we create the pause line we clear pauseLinePoints for next possible pause line + // clear the recording state latlng list and add the start point for the new line + currentRecordingStateLatLngs.clear() + currentRecordingStateLatLngs.add(latLng) + createOrUpdateRecordingLine() + } + } + previousExerciseEngineState = exerciseEngineState + } + + private fun createOrUpdateRecordingLine() { + currentRecordingStateLine?.let { + // we update the latlng list for currentRecordingStateLine + it.latLngs = currentRecordingStateLatLngs + // We update the currentRecordingStateLine only when the mapview is visible + if (isMapViewVisible) { + lineManager.update(it) + Timber.d("Recording state line is updated") + } + } ?: run { + if (currentRecordingStateLatLngs.size > 1) { + Timber.d("Recording state line is created") + currentRecordingStateLine = lineManager.createRecordingStateLine(currentRecordingStateLatLngs) + } + } + } + + private fun exerciseResumed(exerciseEngineState: ExerciseEngineState?) = + previousExerciseEngineState == ExerciseEngineState.Paused && exerciseEngineState == ExerciseEngineState.Recording + + private fun exercisePaused(exerciseEngineState: ExerciseEngineState?) = + previousExerciseEngineState == ExerciseEngineState.Recording && exerciseEngineState == ExerciseEngineState.Paused + + private fun exerciseRecording(exerciseEngineState: ExerciseEngineState?) = + previousExerciseEngineState == ExerciseEngineState.Recording && exerciseEngineState == ExerciseEngineState.Recording + + internal fun onDestroy() { + lineManager.onDestroy() + symbolManager.onDestroy() + } + + internal fun onResume() { + isMapViewVisible = true + createOrUpdateRecordingLine() + } + + internal fun onStop() { + isMapViewVisible = false + } + + override fun onStaleStateChange(isStale: Boolean) { + if (isStale) { + map.locationComponent.removeOnLocationStaleListener(this) + fromStaleState = isStale + } + } +}
\ No newline at end of file diff --git a/mapbox/src/main/java/com/example/mapbox/breadcrumb/ExerciseEngineState.kt b/mapbox/src/main/java/com/example/mapbox/breadcrumb/ExerciseEngineState.kt new file mode 100644 index 0000000000..1d78bb7035 --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/breadcrumb/ExerciseEngineState.kt @@ -0,0 +1,6 @@ +package com.example.mapbox.breadcrumb + +enum class ExerciseEngineState { + Paused, + Recording +}
\ No newline at end of file diff --git a/mapbox/src/main/java/com/example/mapbox/compass/WassCompassEngine.kt b/mapbox/src/main/java/com/example/mapbox/compass/WassCompassEngine.kt new file mode 100644 index 0000000000..6795ea68c4 --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/compass/WassCompassEngine.kt @@ -0,0 +1,48 @@ +package com.soy.android.maps.compass + +import android.hardware.SensorManager.SENSOR_STATUS_ACCURACY_HIGH +import androidx.lifecycle.Observer +import com.example.mapbox.livedata.HeadingSensorLiveData +import com.mapbox.mapboxsdk.location.CompassEngine +import com.mapbox.mapboxsdk.location.CompassListener + +class WassCompassEngine( + private val headingSensorLiveData: HeadingSensorLiveData? +) : CompassEngine { + + private val compassListeners = mutableListOf<CompassListener>() + + private var lastHeading: Float = 0.0f + + private val headingObserver: Observer<Float> = Observer { + lastHeading = Math.toDegrees(it.toDouble()).toFloat() + notifyCompassChangeListeners(lastHeading) + } + + /** + * Always returns [SENSOR_STATUS_ACCURACY_HIGH] and should not mean anything in this context + */ + override fun getLastAccuracySensorStatus() = SENSOR_STATUS_ACCURACY_HIGH + + override fun addCompassListener(compassListener: CompassListener) { + compassListeners.add(compassListener) + } + + override fun removeCompassListener(compassListener: CompassListener) { + compassListeners.remove(compassListener) + } + + override fun getLastHeading() = lastHeading + + fun requestUpdates() = headingSensorLiveData?.observeForever(headingObserver) + + fun removeUpdates() = headingSensorLiveData?.removeObserver(headingObserver) + + private fun notifyCompassChangeListeners(heading: Float) { + lastHeading = heading.apply { + for (compassListener in compassListeners) { + compassListener.onCompassChanged(this) + } + } + } +} diff --git a/mapbox/src/main/java/com/example/mapbox/di/AppComponent.kt b/mapbox/src/main/java/com/example/mapbox/di/AppComponent.kt new file mode 100644 index 0000000000..039ca746c0 --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/di/AppComponent.kt @@ -0,0 +1,19 @@ +import com.example.mapbox.MainActivityModule +import com.example.mapbox.MapboxApp +import dagger.Component +import dagger.android.AndroidInjector +import dagger.android.support.AndroidSupportInjectionModule +import javax.inject.Singleton + +/** + * Application component refers to application level modules only + */ +@Singleton +@Component(modules = [ + AndroidSupportInjectionModule::class, + MainActivityModule::class +]) +interface AppComponent : AndroidInjector<MapboxApp> { + @Component.Builder + abstract class Builder : AndroidInjector.Builder<MapboxApp>() +}
\ No newline at end of file diff --git a/mapbox/src/main/java/com/example/mapbox/extensions/AnnotationsExtensions.kt b/mapbox/src/main/java/com/example/mapbox/extensions/AnnotationsExtensions.kt new file mode 100644 index 0000000000..be4f09d9ff --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/extensions/AnnotationsExtensions.kt @@ -0,0 +1,48 @@ +package com.soy.android.maps.breadcrumb + +import com.example.mapbox.ui.PAUSE_LINE_PATTERN +import com.example.mapbox.ui.START_SYMBOL_ICON_ID +import com.mapbox.mapboxsdk.geometry.LatLng +import com.mapbox.mapboxsdk.plugins.annotation.* +import com.mapbox.mapboxsdk.style.layers.Property + +private const val MAP_LINE_WIDTH = 4f // In pixels +private const val COLOR_MAP_LINE_REGULAR = "#FF5640" +private const val COLOR_MAP_LINE_PAUSE = "#00000000" +private const val MAP_LINE_PAUSE_OPACITY = 0.2f + +internal fun SymbolManager.addStartExerciseSymbol(latLng: LatLng) { + val option = SymbolOptions() + .withLatLng(latLng) + .withIconImage(START_SYMBOL_ICON_ID) + this.create(option) +} + +internal fun LineManager.createRecordingStateLine(recordingStateLatLngs: List<LatLng>): Line { + lineCap = Property.LINE_CAP_BUTT + val lineOptions = LineOptions() + .withLatLngs(recordingStateLatLngs) + .withLineJoin(Property.LINE_JOIN_ROUND) + .withLineColor(COLOR_MAP_LINE_REGULAR) + .withLineWidth(MAP_LINE_WIDTH) + return this.create(lineOptions) +} + +internal fun LineManager.createPausedStateLine(startEndPoints: List<LatLng>): Line { + val lineOptions = LineOptions() + .withLatLngs(startEndPoints) + .withLineJoin(Property.LINE_JOIN_ROUND) + .withLineColor(COLOR_MAP_LINE_PAUSE) + .withLineWidth(MAP_LINE_WIDTH) + .withLinePattern(PAUSE_LINE_PATTERN) + return this.create(lineOptions) +} + +internal fun LineManager.createStaleStateLine(startEndPoints: List<LatLng>): Line { + val lineOptions = LineOptions() + .withLatLngs(startEndPoints) + .withLineJoin(Property.LINE_JOIN_ROUND) + .withLineColor(COLOR_MAP_LINE_REGULAR) + .withLineWidth(MAP_LINE_WIDTH) + return this.create(lineOptions) +}
\ No newline at end of file diff --git a/mapbox/src/main/java/com/example/mapbox/extensions/LocationExtensions.kt b/mapbox/src/main/java/com/example/mapbox/extensions/LocationExtensions.kt new file mode 100644 index 0000000000..67bebf7504 --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/extensions/LocationExtensions.kt @@ -0,0 +1,8 @@ +package com.example.mapbox.extensions + +import android.location.Location +import com.mapbox.mapboxsdk.geometry.LatLng + +fun Location.latLong(): LatLng { + return LatLng(latitude, longitude) +}
\ No newline at end of file diff --git a/mapbox/src/main/java/com/example/mapbox/extensions/MapboxMapExtensions.kt b/mapbox/src/main/java/com/example/mapbox/extensions/MapboxMapExtensions.kt new file mode 100644 index 0000000000..eb863f9f64 --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/extensions/MapboxMapExtensions.kt @@ -0,0 +1,22 @@ +package com.soy.android.maps.extensions + +import com.mapbox.mapboxsdk.location.modes.CameraMode +import com.mapbox.mapboxsdk.maps.MapboxMap +import com.mapbox.mapboxsdk.maps.Style +import kotlinx.coroutines.suspendCancellableCoroutine +import timber.log.Timber +import kotlin.coroutines.resume + +fun MapboxMap.isCameraInTrackingMode() = getActivatedLocationComponent()?.run { + cameraMode == CameraMode.TRACKING_COMPASS || + cameraMode == CameraMode.TRACKING || + cameraMode == CameraMode.TRACKING_GPS || + cameraMode == CameraMode.TRACKING_GPS_NORTH +} + +fun MapboxMap.getActivatedLocationComponent() = locationComponent.takeIf { + it.isLocationComponentEnabled +} ?: run { + Timber.w("Calling location component, but it is not enabled.") + null +} diff --git a/mapbox/src/main/java/com/example/mapbox/extensions/ResourceExtensions.kt b/mapbox/src/main/java/com/example/mapbox/extensions/ResourceExtensions.kt new file mode 100644 index 0000000000..785ed32840 --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/extensions/ResourceExtensions.kt @@ -0,0 +1,25 @@ +package com.example.mapbox.extensions + +import android.content.res.Resources +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable +import androidx.annotation.DrawableRes + +fun Resources.getBitmapFromDrawable(@DrawableRes drawableResId: Int): Bitmap { + return getDrawable(drawableResId, null).getBitmapFromDrawable() +} + +fun Drawable.getBitmapFromDrawable(): Bitmap { + return if (this is BitmapDrawable) { + bitmap + } else { + val bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888) + Canvas(bitmap).let { + setBounds(0, 0, it.width, it.height) + draw(it) + bitmap + } + } +}
\ No newline at end of file diff --git a/mapbox/src/main/java/com/example/mapbox/livedata/HeadingSensorLiveData.kt b/mapbox/src/main/java/com/example/mapbox/livedata/HeadingSensorLiveData.kt new file mode 100644 index 0000000000..4acbfb754a --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/livedata/HeadingSensorLiveData.kt @@ -0,0 +1,33 @@ +package com.example.mapbox.livedata + +import androidx.lifecycle.LiveData +import com.example.mapbox.mockdata.MockHeadingSensor +import kotlinx.coroutines.* +import javax.inject.Inject + +private const val GPS_FIX_INTERVAL_MILLISEC = 1000L + +class HeadingSensorLiveData @Inject constructor( + private val mockHeadingSensor: MockHeadingSensor +) : LiveData<Float>() { + + private val job = Job() + private val backgroundScope = CoroutineScope(Dispatchers.Default + job) + + override fun onActive() { + super.onActive() + backgroundScope.launch { + while(true) { + delay(GPS_FIX_INTERVAL_MILLISEC) + withContext(Dispatchers.Main) { + value = mockHeadingSensor.generateNextValue() + } + } + } + } + + override fun onInactive() { + job.cancel() + super.onInactive() + } +} diff --git a/mapbox/src/main/java/com/example/mapbox/livedata/LocationSensorLiveData.kt b/mapbox/src/main/java/com/example/mapbox/livedata/LocationSensorLiveData.kt new file mode 100644 index 0000000000..c58f9d39e9 --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/livedata/LocationSensorLiveData.kt @@ -0,0 +1,35 @@ +package com.soy.android.maps.livedata + +import android.location.Location +import androidx.lifecycle.LiveData +import com.asoy.wass.sdk.android.sensor.MockLocationSensor +import kotlinx.coroutines.* +import javax.inject.Inject + +private const val HEADING_INTERVAL_MILLISEC = 500L + +class LocationSensorLiveData +@Inject constructor( + private val mockLocationSensor: MockLocationSensor +) : LiveData<Location>() { + + private val job = Job() + private val backgroundScope = CoroutineScope(Dispatchers.Default + job) + + override fun onActive() { + super.onActive() + backgroundScope.launch { + while (true) { + delay(HEADING_INTERVAL_MILLISEC) + withContext(Dispatchers.Main) { + value = mockLocationSensor.generateNextValue() + } + } + } + } + + override fun onInactive() { + job.cancel() + super.onInactive() + } +} diff --git a/mapbox/src/main/java/com/example/mapbox/livedata/LocationWithHeadingLiveData.kt b/mapbox/src/main/java/com/example/mapbox/livedata/LocationWithHeadingLiveData.kt new file mode 100644 index 0000000000..2d09e9bfd5 --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/livedata/LocationWithHeadingLiveData.kt @@ -0,0 +1,30 @@ +package com.example.mapbox.livedata + +import android.location.Location +import androidx.lifecycle.MediatorLiveData +import com.soy.android.maps.livedata.LocationSensorLiveData +import javax.inject.Inject + +/** + * [MediatorLiveData] wrapper used to expose the [AndroidLocation]. + * + * The value is mediated based on the last recorded values of [LocationSensorLiveData] + * and [HeadingSensorLiveData], and each time [LocationSensorLiveData] emits a value + * a new [AndroidLocation] value is emitted by this mediator live data. Note that if + */ +class LocationWithHeadingLiveData +@Inject constructor( + headingSensorLiveData: HeadingSensorLiveData, + locationSensorLiveData: LocationSensorLiveData +) : MediatorLiveData<Location>() { + init { + addSource(locationSensorLiveData) { + headingSensorLiveData.value?.let {heading -> + // Convert radian to degree + it.bearing = Math.toDegrees(heading.toDouble()).toFloat() + value = it + } + } + addSource(headingSensorLiveData) {} + } +} diff --git a/mapbox/src/main/java/com/example/mapbox/livedata/MapViewSensors.kt b/mapbox/src/main/java/com/example/mapbox/livedata/MapViewSensors.kt new file mode 100644 index 0000000000..8b56fff3f6 --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/livedata/MapViewSensors.kt @@ -0,0 +1,37 @@ +package com.soy.android.maps.livedata + +import android.location.Location +import androidx.lifecycle.Observer +import com.example.mapbox.livedata.HeadingSensorLiveData +import com.example.mapbox.livedata.LocationWithHeadingLiveData +import javax.inject.Inject + +class MapViewSensors +@Inject constructor( + val locationLiveData: LocationWithHeadingLiveData, + val headingLiveData: HeadingSensorLiveData +) { + fun requestUpdates( + locationObserver: Observer<Location>? = null, + headingObserver: Observer<Float>? = null + ) { + locationObserver?.let { + locationLiveData.observeForever(it) + } + headingObserver?.let { + headingLiveData.observeForever(it) + } + } + + fun removeUpdates( + locationObserver: Observer<Location>? = null, + headingObserver: Observer<Float>? = null + ) { + locationObserver?.let { + locationLiveData.removeObserver(it) + } + headingObserver?.let { + headingLiveData.removeObserver(it) + } + } +} diff --git a/mapbox/src/main/java/com/example/mapbox/mockdata/MockHeadingSensor.kt b/mapbox/src/main/java/com/example/mapbox/mockdata/MockHeadingSensor.kt new file mode 100644 index 0000000000..9029d89f29 --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/mockdata/MockHeadingSensor.kt @@ -0,0 +1,18 @@ +package com.example.mapbox.mockdata + +import javax.inject.Inject + +class MockHeadingSensor +@Inject constructor() { + + private var heading: Float = 0f + + fun generateNextValue(): Float { + // Rotate 90deg in 10 seconds + heading += 0.1570796326794f + if (heading >= 2.0f * Math.PI.toFloat()) { + heading = 0.0f + } + return heading + } +} diff --git a/mapbox/src/main/java/com/example/mapbox/mockdata/MockLocationSensor.kt b/mapbox/src/main/java/com/example/mapbox/mockdata/MockLocationSensor.kt new file mode 100644 index 0000000000..26d97ba450 --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/mockdata/MockLocationSensor.kt @@ -0,0 +1,31 @@ +package com.asoy.wass.sdk.android.sensor + +import android.location.Location +import android.location.LocationManager +import javax.inject.Inject + +class MockLocationSensor +@Inject constructor() { + + private var currentPosition = 0 + private var step = 1 + + fun generateNextValue(): Location { + val lat = lats[currentPosition] + val long = longs[currentPosition] + currentPosition += step + if (currentPosition >= lats.size) { + step = -1 + currentPosition = lats.size - 1 + } else if (currentPosition <= 0) { + step = 1 + currentPosition = 0 + } + return Location(LocationManager.GPS_PROVIDER).also { location -> + location.accuracy = 0.0f + location.latitude = lat + location.longitude = long + location.altitude = 0.0 + } + } +} diff --git a/mapbox/src/main/java/com/example/mapbox/mockdata/MockLocations.kt b/mapbox/src/main/java/com/example/mapbox/mockdata/MockLocations.kt new file mode 100644 index 0000000000..4d1c4fe6dc --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/mockdata/MockLocations.kt @@ -0,0 +1,661 @@ +package com.asoy.wass.sdk.android.sensor + +// This is just a list of extracted latitudes and longitudes from a real exercise + +internal val lats = listOf(60.22488, 60.22492, 60.22495, 60.22497, 60.225, 60.22502, 60.22505, + 60.22507, 60.22509, 60.22513, 60.22515, 60.22518, 60.2252, 60.22523, 60.22525, 60.22527, + 60.22529, 60.22532, 60.22534, 60.22536, 60.22538, 60.22541, 60.22552, 60.22563, 60.22571, + 60.22576, 60.22579, 60.22587, 60.22597, 60.226, 60.2261, 60.22612, 60.22615, 60.22618, + 60.22622, 60.22627, 60.22629, 60.22631, 60.22633, 60.22635, 60.22637, 60.22639, 60.22642, + 60.22644, 60.22649, 60.22653, 60.2266, 60.22668, 60.22672, 60.22675, 60.22683, 60.22686, + 60.22688, 60.22693, 60.22694, 60.22702, 60.22707, 60.22711, 60.22713, 60.22714, 60.22716, + 60.22717, 60.22718, 60.22719, 60.2272, 60.22722, 60.22723, 60.22724, 60.22724, 60.22725, + 60.22727, 60.22729, 60.2273, 60.22732, 60.22733, 60.22734, 60.22738, 60.2274, 60.22741, + 60.22745, 60.22747, 60.22749, 60.2275, 60.22752, 60.22757, 60.22761, 60.22763, 60.22765, + 60.22767, 60.22768, 60.2277, 60.22771, 60.22772, 60.22773, 60.22775, 60.2278, 60.22782, + 60.22782, 60.22782, 60.22783, 60.22782, 60.22782, 60.22782, 60.2278, 60.22778, 60.22778, + 60.22777, 60.22778, 60.22778, 60.22778, 60.22779, 60.22779, 60.2278, 60.2278, 60.22783, + 60.22783, 60.22784, 60.22784, 60.22784, 60.22784, 60.22784, 60.22784, 60.22785, 60.22787, + 60.22788, 60.22788, 60.22788, 60.22788, 60.22787, 60.22788, 60.22788, 60.22789, 60.22792, + 60.22795, 60.22796, 60.22795, 60.22793, 60.22795, 60.22795, 60.22794, 60.22793, 60.22791, + 60.22789, 60.22787, 60.22786, 60.22784, 60.22783, 60.2278, 60.22779, 60.22775, 60.22774, + 60.22773, 60.22772, 60.22771, 60.2277, 60.22768, 60.22765, 60.22764, 60.22761, 60.2276, + 60.2276, 60.2276, 60.22759, 60.22758, 60.22757, 60.22756, 60.22756, 60.22755, 60.22755, + 60.22754, 60.22753, 60.22752, 60.22752, 60.22752, 60.22753, 60.22754, 60.22755, 60.22756, + 60.22756, 60.22756, 60.22756, 60.22757, 60.22758, 60.22759, 60.22761, 60.22763, 60.22765, + 60.22766, 60.22767, 60.22768, 60.22769, 60.22769, 60.22771, 60.22773, 60.22774, 60.22776, + 60.22777, 60.2278, 60.22782, 60.22783, 60.22785, 60.22786, 60.22788, 60.2279, 60.22792, + 60.22793, 60.22795, 60.22796, 60.22798, 60.22799, 60.22801, 60.22802, 60.22803, 60.22804, + 60.22806, 60.22807, 60.22808, 60.22809, 60.2281, 60.2281, 60.22811, 60.22811, 60.22812, + 60.22813, 60.22813, 60.22813, 60.22815, 60.22817, 60.22818, 60.22818, 60.22819, 60.2282, + 60.22821, 60.22821, 60.22821, 60.22822, 60.22823, 60.22823, 60.22824, 60.22824, 60.22824, + 60.22824, 60.22825, 60.22825, 60.22826, 60.22826, 60.22827, 60.22827, 60.22827, 60.22827, + 60.22826, 60.22826, 60.22825, 60.22825, 60.22825, 60.22825, 60.22825, 60.22825, 60.22825, + 60.22825, 60.22825, 60.22825, 60.22825, 60.22826, 60.22826, 60.22826, 60.22826, 60.22826, + 60.22826, 60.22826, 60.22826, 60.22826, 60.22826, 60.22825, 60.22825, 60.22825, 60.22825, + 60.22825, 60.22824, 60.22825, 60.22825, 60.22825, 60.22825, 60.22825, 60.22826, 60.22826, + 60.22827, 60.22827, 60.22828, 60.22829, 60.22831, 60.22832, 60.22833, 60.22834, 60.22835, + 60.22838, 60.22839, 60.2284, 60.22841, 60.22843, 60.22844, 60.22845, 60.22846, 60.22848, + 60.22849, 60.2285, 60.22851, 60.22851, 60.22852, 60.22853, 60.22854, 60.22854, 60.2285, + 60.22847, 60.22845, 60.22843, 60.2284, 60.22838, 60.22835, 60.22832, 60.22829, 60.22826, + 60.22823, 60.2282, 60.22809, 60.22799, 60.2279, 60.22787, 60.22784, 60.22781, 60.22779, + 60.22776, 60.22774, 60.22771, 60.22768, 60.22765, 60.22763, 60.2276, 60.22757, 60.22755, + 60.22752, 60.22747, 60.22744, 60.22741, 60.22738, 60.22736, 60.22733, 60.2273, 60.2272, + 60.2271, 60.22699, 60.2269, 60.2268, 60.22669, 60.22662, 60.22654, 60.22652, 60.22648, + 60.22646, 60.22645, 60.22642, 60.22639, 60.22637, 60.22636, 60.22627, 60.22618, 60.2261, + 60.22602, 60.22594, 60.22591, 60.22588, 60.22585, 60.22583, 60.2258, 60.22578, 60.22575, + 60.22573, 60.22571, 60.2257, 60.22568, 60.22567, 60.22566, 60.22566, 60.22568, 60.22572, + 60.22573, 60.22576, 60.22579, 60.22582, 60.22585, 60.22587, 60.2259, 60.22592, 60.22594, + 60.22595, 60.22596, 60.22597, 60.22599, 60.22601, 60.22604, 60.22605, 60.22607, 60.22608, + 60.2261, 60.22611, 60.22613, 60.22614, 60.22616, 60.22619, 60.22622, 60.22624, 60.22625, + 60.22626, 60.22629, 60.22633, 60.22635, 60.22637, 60.2264, 60.22643, 60.22647, 60.22649, + 60.22651, 60.22652, 60.22654, 60.22655, 60.22658, 60.22659, 60.22661, 60.22662, 60.22665, + 60.22666, 60.22668, 60.2267, 60.22671, 60.22673, 60.22675, 60.22677, 60.2268, 60.22682, + 60.22689, 60.22691, 60.22694, 60.22696, 60.22699, 60.22702, 60.22704, 60.22706, 60.22709, + 60.22712, 60.22714, 60.22722, 60.22727, 60.22732, 60.22736, 60.22739, 60.22742, 60.22744, + 60.22748, 60.22751, 60.22754, 60.22756, 60.22759, 60.22762, 60.22765, 60.22767, 60.2277, + 60.22772, 60.22774, 60.22776, 60.22778, 60.2278, 60.22782, 60.22784, 60.22786, 60.22787, + 60.22789, 60.22791, 60.22793, 60.22795, 60.22797, 60.228, 60.22802, 60.22804, 60.22807, + 60.22811, 60.22814, 60.22818, 60.2282, 60.22823, 60.22825, 60.22827, 60.22829, 60.22831, + 60.22834, 60.22837, 60.22839, 60.22841, 60.22844, 60.22845, 60.22847, 60.22849, 60.22855, + 60.22858, 60.2286, 60.22863, 60.22866, 60.22869, 60.22872, 60.22875, 60.22877, 60.22881, + 60.22884, 60.22886, 60.22888, 60.22892, 60.22895, 60.22897, 60.22899, 60.22903, 60.22906, + 60.22909, 60.22913, 60.22917, 60.22922, 60.22925, 60.22928, 60.22931, 60.22935, 60.22938, + 60.22942, 60.22945, 60.22948, 60.22951, 60.22954, 60.22957, 60.2296, 60.22962, 60.22965, + 60.22968, 60.22978, 60.22986, 60.22987, 60.22989, 60.2299, 60.22992, 60.22995, 60.22997, + 60.22999, 60.23001, 60.23003, 60.23005, 60.23011, 60.23014, 60.2302, 60.23029, 60.23033, + 60.23038, 60.23042, 60.23043, 60.23045, 60.23046, 60.23045, 60.23043, 60.23043, 60.2304, + 60.23038, 60.23034, 60.2303, 60.23029, 60.23025, 60.2302, 60.23015, 60.23014, 60.23008, + 60.23001, 60.22994, 60.22987, 60.22982, 60.22978, 60.22976, 60.22973, 60.22969, 60.22962, + 60.22955, 60.22945, 60.22938, 60.22929, 60.22926, 60.22923, 60.22921, 60.22919, 60.22917, + 60.22916, 60.22913, 60.22912, 60.2291, 60.22909, 60.22905, 60.22899, 60.22893, 60.22889, + 60.22886, 60.22882, 60.22878, 60.22873, 60.22869, 60.22865, 60.22863, 60.22863, 60.22862, + 60.22862, 60.22861, 60.2286, 60.22859, 60.22858, 60.22858, 60.22858, 60.22858, 60.22858, + 60.22858, 60.22858, 60.22858, 60.22858, 60.22858, 60.22859, 60.22859, 60.2286, 60.2286, + 60.2286, 60.2286, 60.22861, 60.2286, 60.22859, 60.22858, 60.22856, 60.22855, 60.22853, + 60.22852, 60.22851, 60.2285, 60.22848, 60.22841, 60.22839, 60.22836, 60.22834, 60.22832, + 60.22829, 60.22827, 60.22824, 60.22822, 60.2282, 60.22818, 60.22815, 60.22813, 60.22811, + 60.22808, 60.22805, 60.22802, 60.228, 60.22797, 60.22794, 60.22791, 60.22789, 60.22787, + 60.22784, 60.22782, 60.22779, 60.22777, 60.22774, 60.22771, 60.22769, 60.22766, 60.22764, + 60.22761, 60.22759, 60.22757, 60.22754, 60.22752, 60.2275, 60.22747, 60.22744, 60.22742, + 60.2274, 60.22738, 60.22736, 60.22734, 60.22732, 60.22729, 60.22727, 60.22725, 60.22722, + 60.22719, 60.22716, 60.22714, 60.22712, 60.22709, 60.22707, 60.22704, 60.22702, 60.22699, + 60.22697, 60.22694, 60.22692, 60.22689, 60.22687, 60.22684, 60.22682, 60.2268, 60.22677, + 60.22675, 60.22673, 60.2267, 60.22668, 60.22666, 60.22663, 60.22661, 60.22659, 60.22656, + 60.22654, 60.22651, 60.22649, 60.22647, 60.22645, 60.22642, 60.2264, 60.22638, 60.22635, + 60.22633, 60.22631, 60.22629, 60.22627, 60.22624, 60.22622, 60.2262, 60.22618, 60.22616, + 60.22614, 60.22612, 60.22606, 60.22601, 60.22599, 60.22598, 60.22597, 60.22595, 60.22595, + 60.22594, 60.22592, 60.22591, 60.2259, 60.22589, 60.22588, 60.22586, 60.22585, 60.22582, + 60.22581, 60.2258, 60.22578, 60.22578, 60.22576, 60.22575, 60.22574, 60.22573, 60.22571, + 60.2257, 60.22569, 60.22567, 60.22566, 60.22564, 60.22563, 60.22562, 60.22561, 60.2256, + 60.22558, 60.22557, 60.22555, 60.22554, 60.22552, 60.2255, 60.22548, 60.22547, 60.22546, + 60.22545, 60.22544, 60.22543, 60.22541, 60.22541, 60.2254, 60.22539, 60.22538, 60.22537, + 60.22536, 60.22535, 60.22534, 60.22532, 60.22532, 60.22531, 60.2253, 60.22528, 60.22527, + 60.22525, 60.22524, 60.22523, 60.22521, 60.2252, 60.22518, 60.22517, 60.22516, 60.22515, + 60.22513, 60.22512, 60.22511, 60.2251, 60.2251, 60.22509, 60.22509, 60.22508, 60.22507, + 60.22507, 60.22507, 60.22507, 60.22507, 60.22507, 60.22506, 60.22506, 60.22505, 60.22505, + 60.22504, 60.22503, 60.22503, 60.22502, 60.22502, 60.22501, 60.22501, 60.225, 60.225, + 60.225, 60.225, 60.22499, 60.22499, 60.22497, 60.22496, 60.22496, 60.22496, 60.22496, + 60.22496, 60.22495, 60.22495, 60.22493, 60.22491, 60.22491, 60.22491, 60.22491, 60.22491, + 60.22492, 60.22492, 60.22492, 60.22492, 60.22492, 60.22491, 60.2249, 60.22489, 60.22489, + 60.22488, 60.22488, 60.22488, 60.22486, 60.22485, 60.22484, 60.22484, 60.22483, 60.2248, + 60.22478, 60.22477, 60.22477, 60.22477, 60.22478, 60.22481, 60.22482, 60.22485, 60.22487, + 60.22488, 60.22489, 60.22489, 60.2249, 60.22491, 60.22492, 60.22492, 60.22493, 60.22494, + 60.22495, 60.22496, 60.22498, 60.22499, 60.22499, 60.225, 60.22501, 60.22501, 60.22501, + 60.22501, 60.22501, 60.22501, 60.22502, 60.22502, 60.22504, 60.22504, 60.22505, 60.22508, + 60.22512, 60.22513, 60.22517, 60.22523, 60.22529, 60.22532, 60.22535, 60.22535, 60.22536, + 60.22536, 60.22538, 60.2254, 60.22543, 60.22545, 60.22548, 60.22551, 60.22551, 60.22548, + 60.22547, 60.22547, 60.22546, 60.22546, 60.22544, 60.22543, 60.22542, 60.22541, 60.22539, + 60.22538, 60.22536, 60.22535, 60.22528, 60.22521, 60.22513, 60.22509, 60.22506, 60.22504, + 60.22502, 60.22499, 60.22496, 60.22494, 60.22491, 60.22489, 60.22487, 60.22484, 60.22481, + 60.22479, 60.22476, 60.22473, 60.22471, 60.22468, 60.22466, 60.22463, 60.22461, 60.22458, + 60.22456, 60.22453, 60.2245, 60.22448, 60.22445, 60.22443, 60.2244, 60.22438, 60.22435, + 60.22433, 60.2243, 60.22428, 60.22425, 60.22423, 60.2242, 60.22418, 60.22416, 60.22414, + 60.22412, 60.22409, 60.22407, 60.22405, 60.22402, 60.22401, 60.22398, 60.22396, 60.22392, + 60.2239, 60.22387, 60.22386, 60.22383, 60.22382, 60.22384, 60.22385, 60.22382, 60.22383, + 60.22383, 60.22383, 60.22383, 60.22382, 60.2238, 60.2238, 60.22379, 60.22379, 60.2238, + 60.2238, 60.2238, 60.22381, 60.22382, 60.22383, 60.22384, 60.22384, 60.22385, 60.22385, + 60.22387, 60.22388, 60.2239, 60.22392, 60.22393, 60.22395, 60.22396, 60.22397, 60.22399, + 60.22408, 60.22418, 60.22425, 60.22428, 60.22431, 60.22435, 60.22436, 60.22437, 60.22438, + 60.22439, 60.2244, 60.22442, 60.22446, 60.22451, 60.22455, 60.22446, 60.22444, 60.22442, + 60.22439, 60.22437, 60.22433, 60.22431, 60.22428, 60.22426, 60.22423, 60.22421, 60.22418, + 60.22416, 60.22414, 60.22412, 60.22409, 60.22407, 60.22406, 60.22404, 60.22402, 60.22401, + 60.22399, 60.22397, 60.22396, 60.22394, 60.22392, 60.22389, 60.22387, 60.22386, 60.22384, + 60.22382, 60.2238, 60.22378, 60.22376, 60.22367, 60.22358, 60.2235, 60.22343, 60.22337, + 60.2233, 60.22323, 60.22315, 60.22306, 60.22302, 60.22299, 60.22298, 60.22296, 60.22294, + 60.22293, 60.22291, 60.22283, 60.22274, 60.22266, 60.22259, 60.22253, 60.22245, 60.22236, + 60.22227, 60.22216, 60.22209, 60.22207, 60.22205, 60.222, 60.22198, 60.22196, 60.22194, + 60.22192, 60.2219, 60.22188, 60.22185, 60.22182, 60.2218, 60.22177, 60.22175, 60.22173, + 60.2217, 60.22168, 60.22166, 60.22164, 60.22162, 60.22159, 60.22157, 60.22155, 60.22152, + 60.2215, 60.22148, 60.22145, 60.22143, 60.22141, 60.22139, 60.22136, 60.22134, 60.22131, + 60.22129, 60.22126, 60.22124, 60.22122, 60.2212, 60.22119, 60.22114, 60.2211, 60.22105, + 60.221, 60.22097, 60.22093, 60.22091, 60.22091, 60.22091, 60.2209, 60.22086, 60.22083, + 60.22079, 60.2207, 60.22067, 60.22066, 60.22065, 60.22064, 60.22063, 60.22062, 60.2206, + 60.22058, 60.22057, 60.22056, 60.22055, 60.22054, 60.22053, 60.22052, 60.22052, 60.22051, + 60.2205, 60.2205, 60.22049, 60.22048, 60.22048, 60.22047, 60.22046, 60.22045, 60.22044, + 60.22043, 60.22042, 60.22041, 60.2204, 60.2204, 60.22039, 60.22038, 60.22037, 60.22036, + 60.22036, 60.22034, 60.22033, 60.22033, 60.22032, 60.22032, 60.22031, 60.2203, 60.2203, + 60.22029, 60.22029, 60.22029, 60.22029, 60.22029, 60.22029, 60.22029, 60.22028, 60.22027, + 60.22023, 60.22022, 60.2202, 60.22018, 60.22016, 60.22014, 60.22012, 60.2201, 60.22007, + 60.22005, 60.22002, 60.21999, 60.21997, 60.21994, 60.21992, 60.2199, 60.21987, 60.21985, + 60.21983, 60.21981, 60.21979, 60.21977, 60.21974, 60.21971, 60.21969, 60.21967, 60.21964, + 60.21961, 60.21957, 60.21954, 60.21952, 60.21949, 60.21946, 60.21943, 60.2194, 60.21937, + 60.21934, 60.21931, 60.21929, 60.21926, 60.21924, 60.21921, 60.21919, 60.21916, 60.21914, + 60.21912, 60.2191, 60.21907, 60.21905, 60.21902, 60.219, 60.21898, 60.21895, 60.21892, + 60.2189, 60.21887, 60.21885, 60.21882, 60.2188, 60.21877, 60.21874, 60.21872, 60.21869, + 60.21867, 60.21865, 60.21862, 60.2186, 60.21857, 60.21854, 60.21851, 60.21848, 60.21845, + 60.21842, 60.21839, 60.21837, 60.21834, 60.21832, 60.21831, 60.21828, 60.21826, 60.21823, + 60.21821, 60.21819, 60.2181, 60.21808, 60.21806, 60.21802, 60.21799, 60.21797, 60.21794, + 60.21792, 60.21789, 60.21787, 60.21784, 60.21781, 60.21778, 60.21776, 60.21773, 60.21771, + 60.21769, 60.21766, 60.21764, 60.21762, 60.2176, 60.21757, 60.21755, 60.21753, 60.21751, + 60.21749, 60.21747, 60.21745, 60.21741, 60.21738, 60.21736, 60.21733, 60.2173, 60.21728, + 60.21726, 60.21724, 60.21721, 60.21719, 60.21717, 60.21714, 60.21712, 60.21709, 60.21707, + 60.21704, 60.21702, 60.21699, 60.21697, 60.21695, 60.21693, 60.2169, 60.21689, 60.21686, + 60.21684, 60.21673, 60.21663, 60.21661, 60.21658, 60.21656, 60.21654, 60.2165, 60.21644, + 60.21643, 60.21639, 60.21637, 60.21634, 60.21632, 60.2163, 60.21628, 60.21626, 60.21624, + 60.21621, 60.21619, 60.21616, 60.21614, 60.21611, 60.21609, 60.21607, 60.21603, 60.216, + 60.21598, 60.21596, 60.21593, 60.2159, 60.21586, 60.21583, 60.2158, 60.21577, 60.21575, + 60.21572, 60.2157, 60.21567, 60.21563, 60.21561, 60.21558, 60.21556, 60.21553, 60.21546, + 60.21544, 60.21541, 60.21539, 60.21536, 60.21534, 60.21532, 60.2153, 60.21529, 60.21528, + 60.21527, 60.21525, 60.21524, 60.21523, 60.21522, 60.21521, 60.2152, 60.2152, 60.21519, + 60.21519, 60.21518, 60.21518, 60.21518, 60.21518, 60.21518, 60.21517, 60.21516, 60.21516, + 60.21515, 60.21514, 60.21514, 60.21514, 60.21513, 60.21513, 60.21513, 60.21512, 60.21513, + 60.21513, 60.21513, 60.21514, 60.21514, 60.21515, 60.21516, 60.21516, 60.21518, 60.21519, + 60.21524, 60.2153, 60.21537, 60.21541, 60.21543, 60.21547, 60.21547, 60.21548, 60.21549, + 60.2155, 60.21551, 60.21552, 60.21553, 60.21553, 60.21553, 60.21552, 60.21552, 60.21551, + 60.2155, 60.21549, 60.21549, 60.21548, 60.21547, 60.21546, 60.21544, 60.21543, 60.21541, + 60.21539, 60.21538, 60.21536, 60.21534, 60.21532, 60.2153, 60.21528, 60.21525, 60.21523, + 60.21521, 60.21519, 60.21517, 60.21515, 60.21512, 60.2151, 60.21507, 60.21505, 60.21503, + 60.21501, 60.21499, 60.21497, 60.21495, 60.21493, 60.21491, 60.2149, 60.21488, 60.21486, + 60.21485, 60.21483, 60.21482, 60.21481, 60.21479, 60.21478, 60.21477, 60.21475, 60.21475, + 60.21474, 60.21473, 60.21472, 60.21471, 60.2147, 60.2147, 60.2147, 60.21469, 60.21469, + 60.21469, 60.21468, 60.21468, 60.21468, 60.21468, 60.21468, 60.21468, 60.21468, 60.21468, + 60.21467, 60.21467, 60.21467, 60.21467, 60.21466, 60.21466, 60.21466, 60.21465, 60.21464, + 60.21464, 60.21463, 60.21463, 60.21462, 60.21462, 60.21461, 60.21461, 60.21461, 60.21461, + 60.21461, 60.21461, 60.2146, 60.21459, 60.21458, 60.21458, 60.21457, 60.21457, 60.21456, + 60.21456, 60.21456, 60.21455, 60.21455, 60.21454, 60.21454, 60.21453, 60.21453, 60.21452, + 60.21452, 60.21451, 60.2145, 60.2145, 60.2145, 60.21449, 60.21449, 60.2145, 60.2145, + 60.2145, 60.2145, 60.2145, 60.21451, 60.21452, 60.21452, 60.21452, 60.21452, 60.21453, + 60.21453, 60.21453, 60.21453, 60.21453, 60.21453, 60.21452, 60.21452, 60.21452, 60.21451, + 60.2145, 60.2145, 60.21449, 60.21447, 60.21446, 60.21444, 60.21443, 60.21442, 60.2144, + 60.2144, 60.21438, 60.21437, 60.21437, 60.21436, 60.21436, 60.21435, 60.21435, 60.21435, + 60.21434, 60.21433, 60.21433, 60.21432, 60.21431, 60.2143, 60.2143, 60.21429, 60.21429, + 60.21428, 60.21426, 60.21425, 60.21424, 60.21423, 60.21422, 60.2142, 60.21419, 60.21418, + 60.21416, 60.21415, 60.21414, 60.21412, 60.21411, 60.2141, 60.21408, 60.21407, 60.21405, + 60.21404, 60.21403, 60.21401, 60.214, 60.21398, 60.21397, 60.21395, 60.21393, 60.21391, + 60.21389, 60.21388, 60.21386, 60.21385, 60.21383, 60.21382, 60.21381, 60.21379, 60.21378, + 60.21376, 60.21375, 60.21374, 60.21372, 60.2137, 60.21368, 60.21367, 60.21365, 60.21364, + 60.21362, 60.21361, 60.2136, 60.21358, 60.21357, 60.21356, 60.21355, 60.21354, 60.21353, + 60.21352, 60.21351, 60.2135, 60.21348, 60.21347, 60.21345, 60.21344, 60.21342, 60.21341, + 60.2134, 60.21339, 60.21338, 60.21337, 60.21336, 60.21336, 60.21335, 60.21334, 60.21334, + 60.21333, 60.21333, 60.21333, 60.21333, 60.21333, 60.21333, 60.21332, 60.2133, 60.21329, + 60.21328, 60.21326, 60.21325, 60.21321, 60.21319, 60.21316, 60.21314, 60.21311, 60.21308, + 60.21304, 60.21301, 60.21298, 60.21294, 60.21291, 60.21288, 60.21285, 60.21282, 60.21279, + 60.21276, 60.21274, 60.21271, 60.21268, 60.21266, 60.21263, 60.2126, 60.21258, 60.21255, + 60.21252, 60.2125, 60.21247, 60.21244, 60.21241, 60.21238, 60.21235, 60.21233, 60.2123, + 60.21228, 60.21225, 60.21222, 60.21219, 60.21217, 60.21214, 60.21212, 60.2121, 60.21208, + 60.21206, 60.21204, 60.21202, 60.212, 60.21199, 60.21198, 60.21196, 60.21196, 60.21196, + 60.21196, 60.21195, 60.21195, 60.21196, 60.21195, 60.21196, 60.21196, 60.21196, 60.21196, + 60.21196, 60.21195, 60.21194, 60.21193, 60.21191, 60.2119, 60.21188, 60.21186, 60.21185, + 60.21182, 60.2118, 60.21178, 60.21175, 60.21173, 60.21171, 60.21169, 60.21167, 60.21166, + 60.21164, 60.21163, 60.21161, 60.21159, 60.21158, 60.21157, 60.21155, 60.21154, 60.21153, + 60.21152, 60.21151, 60.2115, 60.21149, 60.21148, 60.21146, 60.21145, 60.21144, 60.21143, + 60.21142, 60.21141, 60.21139, 60.21138, 60.21138, 60.21138, 60.21138, 60.21139, 60.21141, + 60.21143, 60.21146, 60.21149, 60.21152, 60.21154, 60.21157, 60.21159, 60.21162, 60.21164, + 60.21167, 60.21169, 60.21172, 60.21174, 60.21177, 60.21179, 60.21181, 60.21184, 60.21186, + 60.21189, 60.21191, 60.21194, 60.21196, 60.21199, 60.21201, 60.21204, 60.21206, 60.21208, + 60.21211, 60.21213, 60.21215, 60.21217, 60.2122, 60.21222, 60.21224, 60.21227, 60.21229, + 60.21231, 60.21234, 60.21236, 60.21238, 60.2124, 60.21243, 60.21245, 60.21247, 60.21249, + 60.21252, 60.21254, 60.21257, 60.21259, 60.21261, 60.21263, 60.21266, 60.21268, 60.21271, + 60.21273, 60.21276, 60.21278, 60.2128, 60.21283, 60.21285, 60.21288, 60.2129, 60.21293, + 60.21295, 60.21297, 60.213, 60.21302, 60.21304, 60.21307, 60.2131, 60.21312, 60.21315, + 60.21317, 60.2132, 60.21322, 60.21325, 60.21327, 60.2133, 60.21332, 60.21335, 60.21337, + 60.2134, 60.21342, 60.21345, 60.21347, 60.21349, 60.21351, 60.21354, 60.21356, 60.21358, + 60.2136, 60.21363, 60.21365, 60.21367, 60.21369, 60.21372, 60.21374, 60.21377, 60.21379, + 60.21382, 60.21384, 60.21386, 60.21389, 60.21391, 60.21394, 60.21396, 60.21399, 60.21401, + 60.21404, 60.21406, 60.21409, 60.21412, 60.21414, 60.21416, 60.21419, 60.21421, 60.21424, + 60.21426, 60.21429, 60.21431, 60.21433, 60.21436, 60.21438, 60.21441, 60.21443, 60.21445, + 60.21448, 60.2145, 60.21453, 60.21456, 60.21458, 60.2146, 60.21463, 60.21465, 60.21467, + 60.2147, 60.21472, 60.21474, 60.21477, 60.21479, 60.21481, 60.21484, 60.21486, 60.21489, + 60.21491, 60.21494, 60.21496, 60.21499, 60.21501, 60.21504, 60.21506, 60.21509, 60.21511, + 60.21513, 60.21516, 60.21518, 60.21521, 60.21523, 60.21526, 60.21528, 60.21531, 60.21533, + 60.21536, 60.21538, 60.21541, 60.21543, 60.21546, 60.21548, 60.21551, 60.21554, 60.21556, + 60.21558, 60.21561, 60.21564, 60.21566, 60.21569, 60.21571, 60.21573, 60.21576, 60.21578, + 60.21581, 60.21583, 60.21585, 60.21588, 60.2159, 60.21592, 60.21595, 60.21597, 60.216, + 60.21602, 60.21604, 60.21606, 60.21609, 60.21611, 60.21613, 60.21616, 60.21618, 60.2162, + 60.21623, 60.21625, 60.21627, 60.2163, 60.21632, 60.21634, 60.21637, 60.21639, 60.21642, + 60.21644, 60.21646, 60.21649, 60.21651, 60.21653, 60.21654, 60.21654, 60.21655, 60.21656, + 60.21658, 60.2166, 60.21662, 60.21664, 60.21666, 60.21668, 60.21671, 60.21673, 60.21675, + 60.21677, 60.21679, 60.21681, 60.21683, 60.21684, 60.21686, 60.21687, 60.21689, 60.21691, + 60.21692, 60.21693, 60.21695, 60.21696, 60.21698, 60.217, 60.21702, 60.21704, 60.21706, + 60.21708, 60.2171, 60.21711, 60.21713, 60.21716, 60.21719, 60.21721, 60.21722, 60.21724, + 60.21727, 60.21729, 60.21731, 60.21733, 60.21735, 60.21737, 60.21739, 60.2174, 60.21742, + 60.21744, 60.21745, 60.21747, 60.21748, 60.21749, 60.2175, 60.21752, 60.21752, 60.21754, + 60.21755, 60.21757, 60.21762, 60.2177, 60.21778, 60.21786, 60.21794, 60.21796, 60.21801, + 60.21806, 60.21809, 60.21812, 60.21813, 60.21814, 60.21815, 60.21815, 60.21816, 60.21816, + 60.21816, 60.21816, 60.21816, 60.21817, 60.21818, 60.21819, 60.2182, 60.2182, 60.21827, + 60.21836, 60.21844, 60.21852, 60.21858, 60.21865, 60.2187, 60.21873, 60.21875, 60.21877, + 60.21877, 60.21878, 60.21879, 60.2188, 60.21882, 60.21883, 60.21883, 60.21884, 60.21884, + 60.21884, 60.21884, 60.21885, 60.21884, 60.21884, 60.21884, 60.21883, 60.21882, 60.21881, + 60.2188, 60.21879, 60.21878, 60.21878, 60.21878, 60.21878, 60.21878, 60.21878, 60.21879, + 60.21879, 60.2188, 60.21881, 60.21882, 60.21883, 60.21883, 60.21884, 60.21884, 60.21885, + 60.21885, 60.21886, 60.21887, 60.21888, 60.21888, 60.21889, 60.21889, 60.21889, 60.21888, + 60.21889, 60.21889, 60.2189, 60.21891, 60.21892, 60.21894, 60.21896, 60.21898, 60.219, + 60.21902, 60.21904, 60.21906, 60.21908, 60.2191, 60.21912, 60.21914, 60.21916, 60.21918, + 60.2192, 60.21922, 60.21924, 60.21926, 60.21928, 60.2193, 60.21932, 60.21934, 60.21936, + 60.21938, 60.2194, 60.21942, 60.21944, 60.21951, 60.21953, 60.21956, 60.21957, 60.21958, + 60.2196, 60.21963, 60.21971, 60.21976, 60.21977, 60.21979, 60.2198, 60.21983, 60.21984, + 60.21986, 60.21988, 60.2199, 60.21992, 60.21994, 60.21996, 60.21998, 60.21999, 60.22008, + 60.22015, 60.22017, 60.2202, 60.22021, 60.22022, 60.22029, 60.22033, 60.22037, 60.22039, + 60.22041, 60.22043, 60.22045, 60.22047, 60.22049, 60.22051, 60.22053, 60.22056, 60.22058, + 60.2206, 60.22062, 60.22064, 60.22066, 60.22067, 60.22069, 60.22071, 60.22073, 60.22075, + 60.22078, 60.22079, 60.22081, 60.22083, 60.22085, 60.22087, 60.22089, 60.22092, 60.22094, + 60.22096, 60.22098, 60.221, 60.22103, 60.22105, 60.22106, 60.22107, 60.22109, 60.2211, + 60.22112, 60.22113, 60.22114, 60.22115, 60.22117, 60.22118, 60.22119, 60.2212, 60.22122, + 60.22124, 60.22124, 60.22124, 60.22123, 60.22122, 60.22121, 60.2212, 60.2212, 60.2212, + 60.2212, 60.2212, 60.22121, 60.22125, 60.22127, 60.22129, 60.2213, 60.22132, 60.22134, + 60.22136, 60.22138, 60.2214, 60.22142, 60.22144, 60.22146, 60.22148, 60.2215, 60.22153, + 60.22155, 60.22158, 60.2216, 60.22162, 60.22164, 60.22166, 60.22168, 60.2217, 60.22172, + 60.22174, 60.22176, 60.22179, 60.22182, 60.22184, 60.22188, 60.22192, 60.22194, 60.22197, + 60.222, 60.22202, 60.22205, 60.22207, 60.2221, 60.22211, 60.22213, 60.22215, 60.22217, + 60.22219, 60.22222, 60.22224, 60.22227, 60.22229, 60.22232, 60.22234, 60.22236, 60.22237, + 60.22238, 60.22239, 60.22241, 60.22243, 60.22245, 60.22248, 60.2225, 60.22252, 60.22254, + 60.22255, 60.22258, 60.22259, 60.22264, 60.22271, 60.22274, 60.22276, 60.22278, 60.22281, + 60.22283, 60.22287, 60.22289, 60.22292, 60.22294, 60.22297, 60.223, 60.22303, 60.22306, + 60.22309, 60.22312, 60.22316, 60.22318, 60.22321, 60.22324, 60.22328, 60.2233, 60.22332, + 60.22335, 60.22337, 60.22338, 60.2234, 60.22342, 60.22345, 60.22347, 60.22349, 60.22351, + 60.22352, 60.22354, 60.22355, 60.22357, 60.22358, 60.2236, 60.22362, 60.22363, 60.22365, + 60.22368, 60.2237, 60.22371, 60.22373, 60.22375, 60.22377, 60.22378, 60.2238, 60.22381, + 60.22384, 60.22385, 60.22387, 60.22389, 60.22398, 60.22404, 60.22409, 60.2241, 60.22412, + 60.22414, 60.22416, 60.22417, 60.22418, 60.22419, 60.22421, 60.22422, 60.22424, 60.22425, + 60.22427, 60.22429, 60.22431, 60.22434, 60.22436, 60.22439, 60.22441, 60.22443, 60.22445, + 60.22447, 60.22449, 60.22457, 60.22465, 60.22471, 60.22472, 60.22474, 60.22475, 60.22477, + 60.22478, 60.2248, 60.22486, 60.22489, 60.22491, 60.22493, 60.22495, 60.22497, 60.225, + 60.22502, 60.22504, 60.22506, 60.22513, 60.22516, 60.22517, 60.22519, 60.22522, 60.22525, + 60.22527, 60.22529, 60.22531, 60.22533, 60.22535, 60.22537, 60.22539, 60.22542, 60.22544, + 60.22546, 60.22549, 60.22551, 60.22552, 60.22554, 60.22557, 60.22559, 60.22561, 60.22563, + 60.22565, 60.22567, 60.22569, 60.22571, 60.22572, 60.22574, 60.22575, 60.22577, 60.22579, + 60.2258, 60.22582, 60.22584, 60.22586, 60.22588, 60.2259, 60.22591, 60.22593, 60.22595, + 60.22596, 60.22598, 60.226, 60.22602, 60.22605, 60.22607, 60.22609, 60.22611, 60.22612, + 60.22614, 60.22615, 60.22617, 60.22619, 60.2262, 60.22623, 60.22625, 60.22629, 60.22632, + 60.22634, 60.22636, 60.22641, 60.22643, 60.22646, 60.22648, 60.22654, 60.22655, 60.22657, + 60.22658, 60.2266, 60.22662, 60.22664, 60.22666, 60.22668, 60.22671, 60.22673, 60.22676, + 60.22678, 60.22681, 60.22684, 60.22687, 60.22689, 60.22691, 60.22693, 60.22695, 60.22698, + 60.227, 60.22703, 60.22705, 60.22707, 60.22709, 60.22711, 60.22713, 60.22715, 60.22717, + 60.22719, 60.22727, 60.22729, 60.22732, 60.22734, 60.22735, 60.22738, 60.22741, 60.22743, + 60.22744, 60.22747, 60.22751, 60.22753, 60.22755, 60.22757, 60.22759, 60.22761, 60.22763, + 60.22765, 60.22767, 60.22769, 60.22771, 60.22773, 60.22775, 60.22779, 60.22782, 60.22784, + 60.22786, 60.22789, 60.22791, 60.22793, 60.22796, 60.22798, 60.228, 60.22803, 60.22806, + 60.22808, 60.2281, 60.22813, 60.22815, 60.22817, 60.22821, 60.22824, 60.22826, 60.22829, + 60.22832, 60.22835, 60.22838, 60.2284, 60.22842, 60.22844, 60.22846, 60.22848, 60.22849, + 60.2285, 60.2285, 60.2285, 60.2285, 60.22849, 60.22849, 60.22849, 60.22848, 60.22847, + 60.22846, 60.22845, 60.22844, 60.22843, 60.22842, 60.22841, 60.2284, 60.22839, 60.22838, + 60.22837, 60.22836, 60.22835, 60.22834, 60.22833, 60.22832, 60.22831, 60.2283, 60.22829, + 60.22828, 60.22827, 60.22826, 60.22826, 60.22825, 60.22825, 60.22824, 60.22824, 60.22823, + 60.22823, 60.22823, 60.22823, 60.22823, 60.22824, 60.22824, 60.22824, 60.22825, 60.22826, + 60.22826, 60.22827, 60.22827, 60.22827, 60.22827, 60.22827, 60.22827, 60.22827, 60.22827, + 60.22827, 60.22827, 60.22826, 60.22826, 60.22826, 60.22826, 60.22827, 60.22827, 60.22827, + 60.22827, 60.22828, 60.22828, 60.22829, 60.22829, 60.22829, 60.22829, 60.22829, 60.22829, + 60.22829, 60.22829, 60.22829, 60.22829, 60.22829, 60.22829, 60.22829, 60.22829, 60.22829, + 60.22829, 60.22828, 60.22828, 60.22827, 60.22827, 60.22826, 60.22826, 60.22824, 60.22823, + 60.22822, 60.2282, 60.22818, 60.22817, 60.22816, 60.22814, 60.22813, 60.22811, 60.2281, + 60.22808, 60.22807, 60.22805, 60.22804, 60.22803, 60.22802, 60.22801, 60.22799, 60.22798, + 60.22797, 60.22796, 60.22794, 60.22793, 60.22792, 60.2279, 60.22789, 60.22787, 60.22786, + 60.22785, 60.22784, 60.22782, 60.22781, 60.2278, 60.22779, 60.22777, 60.22776, 60.22774, + 60.22773, 60.22771, 60.22769, 60.22767, 60.22765, 60.22763, 60.22761, 60.22759, 60.22757, + 60.22755, 60.22753, 60.22751, 60.22749, 60.22748, 60.22747, 60.22747, 60.22748, 60.22749, + 60.2275, 60.22752, 60.22754, 60.22756, 60.22757, 60.22759, 60.2276, 60.22762, 60.22763, + 60.22764, 60.22766, 60.22767, 60.22767, 60.22768, 60.22768, 60.22768, 60.22768, 60.22769, + 60.2277, 60.2277, 60.22771, 60.22772, 60.22772, 60.22774, 60.22775, 60.22776, 60.22777, + 60.22778, 60.2278, 60.22781, 60.22782, 60.22784, 60.22784, 60.22785, 60.22786, 60.22787, + 60.22788, 60.2279, 60.22792, 60.22793, 60.22795, 60.22797, 60.22799, 60.228, 60.22802, + 60.22803, 60.22804, 60.22804, 60.22803, 60.22801, 60.22798, 60.22796, 60.22793, 60.22791, + 60.22789, 60.22788, 60.22787, 60.22786, 60.22786, 60.22785, 60.22785, 60.22784, 60.22784, + 60.22784, 60.22783, 60.22783, 60.22782, 60.22781, 60.22781, 60.22781, 60.22782, 60.22782, + 60.22782, 60.22782, 60.22782, 60.22782, 60.22781, 60.22781, 60.22781, 60.22781, 60.22782, + 60.22782, 60.22782, 60.22782, 60.22782, 60.22782, 60.22782, 60.22782, 60.22782, 60.22782, + 60.22781, 60.22781, 60.22781, 60.22781, 60.2278, 60.2278, 60.2278, 60.2278, 60.2278, + 60.22779, 60.22779, 60.22779, 60.22778, 60.22777, 60.22776, 60.22776, 60.22775, 60.22775, + 60.22775, 60.22775, 60.22775, 60.22775, 60.22775, 60.22776, 60.22775, 60.22775, 60.22774, + 60.22774, 60.22773, 60.22773, 60.22772, 60.22772, 60.22772, 60.22771, 60.22771, 60.22771, + 60.2277, 60.22769, 60.22767, 60.22765, 60.22763, 60.2276, 60.22759, 60.22757, 60.22756, + 60.22754, 60.22752, 60.2275, 60.22748, 60.22746, 60.22745, 60.22743, 60.22742, 60.2274, + 60.22738, 60.22737, 60.22734, 60.22732, 60.2273, 60.22728, 60.22726, 60.22725, 60.22723, + 60.22721, 60.2272, 60.22718, 60.22717, 60.22715, 60.22713, 60.22711, 60.22709, 60.22706, + 60.22704, 60.22702, 60.22699, 60.22696, 60.22693, 60.22691, 60.22688, 60.22686, 60.22683, + 60.22679, 60.22676, 60.22673, 60.2267, 60.22666, 60.22662, 60.22659, 60.22655, 60.22652, + 60.22649, 60.22645, 60.22642, 60.22638, 60.22635, 60.22632, 60.22629, 60.22626, 60.22622, + 60.22619, 60.22615, 60.22612, 60.22608, 60.22605, 60.22601, 60.22598, 60.22595, 60.22592, + 60.22588, 60.22585, 60.22582, 60.22579, 60.22575, 60.22571, 60.22567, 60.22564, 60.2256, + 60.22556, 60.22552, 60.22548, 60.22545, 60.22541, 60.22537, 60.22534, 60.2253, 60.22526, + 60.22522, 60.22518, 60.22514, 60.2251, 60.22506, 60.22503, 60.22499, 60.22496, 60.22491, + 60.22487) + +internal val longs = listOf(25.07488, 25.07488, 25.07487, 25.07485, 25.07483, 25.07481, 25.07478, + 25.07476, 25.07474, 25.07471, 25.07468, 25.07464, 25.0746, 25.07457, 25.07455, 25.07454, + 25.07452, 25.07451, 25.07448, 25.07447, 25.07445, 25.07443, 25.07436, 25.07429, 25.07419, + 25.07418, 25.07414, 25.07401, 25.07392, 25.07391, 25.07383, 25.07381, 25.0738, 25.07379, + 25.07378, 25.07375, 25.0737, 25.07367, 25.07365, 25.07362, 25.0736, 25.07359, 25.07357, + 25.07355, 25.0735, 25.07346, 25.07335, 25.07322, 25.07315, 25.07312, 25.07301, 25.07298, + 25.07296, 25.07289, 25.07285, 25.07269, 25.07253, 25.07243, 25.07237, 25.07232, 25.07228, + 25.07222, 25.07217, 25.07211, 25.07205, 25.07199, 25.07194, 25.07188, 25.07184, 25.07179, + 25.07175, 25.0717, 25.07164, 25.07159, 25.07155, 25.07151, 25.07142, 25.07138, 25.07132, + 25.07122, 25.07117, 25.07113, 25.0711, 25.07106, 25.07087, 25.07072, 25.07067, 25.07062, + 25.07058, 25.07053, 25.07049, 25.07046, 25.07042, 25.07037, 25.07032, 25.07014, 25.06999, + 25.06994, 25.06974, 25.06954, 25.06935, 25.06915, 25.06897, 25.06889, 25.06881, 25.06861, + 25.06851, 25.06847, 25.06842, 25.06837, 25.06833, 25.06814, 25.06791, 25.06786, 25.06765, + 25.06759, 25.06754, 25.06748, 25.06743, 25.06738, 25.06733, 25.06728, 25.06706, 25.06684, + 25.06673, 25.06669, 25.06664, 25.0666, 25.06655, 25.06637, 25.06618, 25.06595, 25.06575, + 25.06561, 25.06557, 25.06552, 25.06545, 25.06541, 25.06535, 25.06529, 25.06523, 25.06515, + 25.06509, 25.06505, 25.06502, 25.06498, 25.06494, 25.06486, 25.06481, 25.06469, 25.06466, + 25.06462, 25.06457, 25.06453, 25.06447, 25.06429, 25.06409, 25.06386, 25.06371, 25.06367, + 25.06362, 25.06357, 25.06352, 25.06348, 25.06344, 25.06337, 25.06333, 25.06328, 25.06323, + 25.06318, 25.06314, 25.06309, 25.06304, 25.06298, 25.06293, 25.06288, 25.06283, 25.0628, + 25.06275, 25.0627, 25.06264, 25.06259, 25.06254, 25.06248, 25.06243, 25.06239, 25.06234, + 25.06229, 25.06224, 25.06219, 25.06215, 25.06209, 25.06205, 25.062, 25.06195, 25.0619, + 25.06186, 25.06183, 25.0618, 25.06177, 25.06173, 25.06169, 25.06165, 25.0616, 25.06157, + 25.06152, 25.06148, 25.06143, 25.06138, 25.06134, 25.0613, 25.06126, 25.06122, 25.06118, + 25.06113, 25.06109, 25.06104, 25.06099, 25.06095, 25.0609, 25.06086, 25.06082, 25.06078, + 25.06074, 25.06069, 25.06064, 25.0606, 25.06056, 25.06052, 25.06047, 25.06042, 25.06036, + 25.06031, 25.06026, 25.06021, 25.06015, 25.06011, 25.06006, 25.06001, 25.05995, 25.0599, + 25.05985, 25.0598, 25.05975, 25.0597, 25.05965, 25.0596, 25.05955, 25.0595, 25.05946, + 25.05941, 25.05937, 25.05932, 25.05928, 25.05923, 25.05919, 25.05914, 25.0591, 25.05905, + 25.059, 25.05895, 25.0589, 25.05886, 25.05881, 25.05876, 25.05871, 25.05866, 25.05861, + 25.05856, 25.0585, 25.05846, 25.05841, 25.05837, 25.05832, 25.05827, 25.05823, 25.05819, + 25.05815, 25.0581, 25.05805, 25.05801, 25.05797, 25.05792, 25.05787, 25.05782, 25.05776, + 25.05771, 25.05766, 25.0576, 25.05754, 25.05748, 25.05742, 25.05736, 25.0573, 25.05724, + 25.05707, 25.05703, 25.05698, 25.05693, 25.05689, 25.05684, 25.0568, 25.05676, 25.05672, + 25.05668, 25.05663, 25.05659, 25.05654, 25.05649, 25.05644, 25.05638, 25.05633, 25.05619, + 25.05616, 25.05613, 25.0561, 25.05608, 25.05607, 25.05606, 25.05605, 25.05603, 25.05602, + 25.056, 25.05598, 25.05594, 25.05591, 25.05593, 25.05593, 25.05594, 25.05595, 25.05595, + 25.05596, 25.05597, 25.05598, 25.05599, 25.05599, 25.05598, 25.05599, 25.05598, 25.05597, + 25.05597, 25.05595, 25.05595, 25.05593, 25.05592, 25.0559, 25.05589, 25.05588, 25.05576, + 25.05565, 25.05554, 25.05547, 25.05541, 25.05532, 25.05521, 25.0551, 25.05507, 25.05499, + 25.05494, 25.05488, 25.0548, 25.05473, 25.0547, 25.05467, 25.05454, 25.05441, 25.0543, + 25.05418, 25.05407, 25.05404, 25.05397, 25.05392, 25.05388, 25.05383, 25.0538, 25.05375, + 25.05372, 25.0537, 25.05367, 25.05364, 25.0536, 25.05354, 25.05348, 25.05329, 25.05309, + 25.05298, 25.05292, 25.05289, 25.05286, 25.05283, 25.05279, 25.05275, 25.05272, 25.05268, + 25.05265, 25.05261, 25.05258, 25.05255, 25.0525, 25.05244, 25.05241, 25.05237, 25.05233, + 25.0523, 25.05226, 25.05223, 25.0522, 25.05215, 25.05211, 25.05206, 25.05203, 25.052, + 25.05197, 25.05193, 25.05189, 25.05188, 25.05187, 25.05186, 25.05186, 25.05184, 25.05183, + 25.05181, 25.05178, 25.05176, 25.05173, 25.0517, 25.05166, 25.05164, 25.05161, 25.05156, + 25.05153, 25.0515, 25.05148, 25.05146, 25.05143, 25.05141, 25.05136, 25.05133, 25.05131, + 25.05128, 25.05127, 25.05129, 25.05129, 25.05129, 25.05128, 25.05128, 25.05129, 25.0513, + 25.05132, 25.05134, 25.05137, 25.05137, 25.05137, 25.05137, 25.05137, 25.05137, 25.05136, + 25.05136, 25.05135, 25.05133, 25.05131, 25.05129, 25.05128, 25.05126, 25.05124, 25.05121, + 25.05119, 25.05117, 25.05115, 25.05113, 25.05111, 25.05108, 25.05106, 25.05104, 25.05101, + 25.05099, 25.05095, 25.05091, 25.05087, 25.05083, 25.05079, 25.05076, 25.05074, 25.05072, + 25.05072, 25.05071, 25.05069, 25.05069, 25.05067, 25.05065, 25.05063, 25.0506, 25.05058, + 25.05055, 25.05053, 25.05051, 25.05049, 25.05048, 25.05046, 25.05045, 25.05044, 25.05041, + 25.0504, 25.05039, 25.05038, 25.05037, 25.05037, 25.05037, 25.05038, 25.05039, 25.05048, + 25.05049, 25.05049, 25.05049, 25.05048, 25.05045, 25.05045, 25.05045, 25.05045, 25.05046, + 25.05047, 25.05049, 25.05051, 25.05055, 25.0506, 25.05066, 25.05071, 25.05076, 25.05079, + 25.05082, 25.05084, 25.05087, 25.0509, 25.05092, 25.05093, 25.05094, 25.05092, 25.05091, + 25.0509, 25.05081, 25.05064, 25.05059, 25.05054, 25.05049, 25.05044, 25.05039, 25.05034, + 25.05029, 25.05025, 25.0502, 25.05014, 25.04998, 25.04993, 25.04979, 25.0496, 25.04943, + 25.04928, 25.04911, 25.04891, 25.04871, 25.04851, 25.0483, 25.04809, 25.0479, 25.04771, + 25.04751, 25.04732, 25.04712, 25.04693, 25.04676, 25.04658, 25.04638, 25.04631, 25.04614, + 25.04599, 25.04582, 25.04566, 25.04548, 25.04526, 25.04504, 25.04486, 25.04469, 25.0445, + 25.04434, 25.04416, 25.04402, 25.04384, 25.04373, 25.04361, 25.04354, 25.04348, 25.04342, + 25.04336, 25.04331, 25.04327, 25.04322, 25.04316, 25.04298, 25.04281, 25.04265, 25.04243, + 25.04223, 25.04206, 25.04189, 25.04168, 25.04149, 25.04127, 25.04111, 25.04106, 25.04101, + 25.04095, 25.0409, 25.04084, 25.04079, 25.04068, 25.04062, 25.04057, 25.04051, 25.04046, + 25.04041, 25.04035, 25.0403, 25.04025, 25.04019, 25.04013, 25.04007, 25.04001, 25.03995, + 25.03989, 25.03983, 25.03978, 25.03974, 25.0397, 25.03966, 25.0396, 25.03955, 25.03949, + 25.03943, 25.03937, 25.03932, 25.03926, 25.03909, 25.03906, 25.03902, 25.039, 25.03897, + 25.03894, 25.03892, 25.0389, 25.03887, 25.03885, 25.03882, 25.0388, 25.03877, 25.03875, + 25.03872, 25.03869, 25.03867, 25.03864, 25.03861, 25.03859, 25.03856, 25.03855, 25.03852, + 25.03849, 25.03847, 25.03844, 25.03841, 25.03839, 25.03836, 25.03834, 25.03832, 25.03829, + 25.03827, 25.03825, 25.03823, 25.0382, 25.03817, 25.03814, 25.03811, 25.03809, 25.03806, + 25.03804, 25.03801, 25.03799, 25.03797, 25.03794, 25.03792, 25.0379, 25.03788, 25.03785, + 25.03783, 25.0378, 25.03778, 25.03775, 25.03772, 25.0377, 25.03768, 25.03765, 25.03763, + 25.03761, 25.03758, 25.03756, 25.03753, 25.0375, 25.03748, 25.03746, 25.03744, 25.03742, + 25.03739, 25.03736, 25.03733, 25.0373, 25.03727, 25.03724, 25.03722, 25.03719, 25.03717, + 25.03714, 25.03712, 25.0371, 25.03708, 25.03705, 25.03702, 25.037, 25.03698, 25.03695, + 25.03693, 25.0369, 25.03687, 25.03684, 25.03681, 25.03679, 25.03675, 25.03671, 25.03667, + 25.03663, 25.03659, 25.03651, 25.03635, 25.03627, 25.03623, 25.03618, 25.03611, 25.03606, + 25.03602, 25.03595, 25.03591, 25.03586, 25.03581, 25.03576, 25.03573, 25.03569, 25.03565, + 25.03561, 25.03557, 25.03553, 25.03548, 25.03544, 25.03538, 25.03533, 25.03528, 25.03524, + 25.03519, 25.03513, 25.03508, 25.03502, 25.03497, 25.03493, 25.03488, 25.03483, 25.03479, + 25.03474, 25.03469, 25.03464, 25.03459, 25.03454, 25.03448, 25.03443, 25.03438, 25.03433, + 25.03428, 25.03424, 25.03419, 25.03414, 25.0341, 25.03405, 25.034, 25.03396, 25.03392, + 25.03387, 25.03384, 25.0338, 25.03374, 25.03369, 25.03365, 25.0336, 25.03356, 25.03352, + 25.03348, 25.03344, 25.0334, 25.03337, 25.03332, 25.03328, 25.03324, 25.03318, 25.03312, + 25.03306, 25.03301, 25.03295, 25.03289, 25.03284, 25.03279, 25.03274, 25.03269, 25.03263, + 25.03257, 25.03251, 25.03246, 25.0324, 25.03234, 25.03229, 25.03224, 25.03218, 25.03213, + 25.03208, 25.03202, 25.03197, 25.03191, 25.03185, 25.03179, 25.03174, 25.03168, 25.03163, + 25.03157, 25.03152, 25.03147, 25.03142, 25.03137, 25.03132, 25.03127, 25.03122, 25.03117, + 25.03112, 25.03107, 25.03102, 25.0308, 25.03059, 25.03049, 25.03044, 25.03039, 25.03035, + 25.03031, 25.03027, 25.03023, 25.03018, 25.03013, 25.03003, 25.02996, 25.0299, 25.02985, + 25.02978, 25.02973, 25.02968, 25.02947, 25.02942, 25.02937, 25.02932, 25.02927, 25.02905, + 25.02894, 25.02888, 25.02883, 25.0286, 25.02838, 25.02818, 25.02797, 25.02777, 25.02763, + 25.02758, 25.02754, 25.02749, 25.02743, 25.02738, 25.02733, 25.02729, 25.02724, 25.02719, + 25.02714, 25.02709, 25.02704, 25.02699, 25.02693, 25.02687, 25.02682, 25.02676, 25.0267, + 25.02664, 25.02658, 25.02652, 25.02647, 25.02641, 25.02618, 25.02607, 25.02602, 25.02582, + 25.02563, 25.02543, 25.02525, 25.02507, 25.02488, 25.02472, 25.02453, 25.02447, 25.02442, + 25.02437, 25.02429, 25.02419, 25.02411, 25.02407, 25.02399, 25.02382, 25.02362, 25.02347, + 25.02343, 25.02338, 25.02334, 25.02329, 25.02324, 25.02319, 25.02314, 25.02308, 25.02303, + 25.02298, 25.02292, 25.02287, 25.02271, 25.02256, 25.02244, 25.02238, 25.02235, 25.02232, + 25.0223, 25.02228, 25.02226, 25.02224, 25.02221, 25.02219, 25.02216, 25.02213, 25.02211, + 25.02209, 25.02207, 25.02204, 25.02202, 25.02201, 25.02199, 25.02197, 25.02194, 25.02192, + 25.0219, 25.02187, 25.02186, 25.02184, 25.02182, 25.0218, 25.02178, 25.02176, 25.02174, + 25.02172, 25.0217, 25.02168, 25.02166, 25.02164, 25.02161, 25.02158, 25.02156, 25.02154, + 25.02151, 25.02149, 25.02148, 25.02147, 25.02147, 25.02148, 25.02148, 25.02148, 25.02146, + 25.02144, 25.0214, 25.02138, 25.02133, 25.02129, 25.02107, 25.02086, 25.0207, 25.02065, + 25.0206, 25.02056, 25.02051, 25.02044, 25.02037, 25.02031, 25.02011, 25.02004, 25.01999, + 25.01993, 25.01986, 25.01982, 25.01977, 25.01972, 25.01966, 25.01961, 25.01957, 25.01951, + 25.01947, 25.01942, 25.01938, 25.01935, 25.01931, 25.01927, 25.01922, 25.01917, 25.01914, + 25.01901, 25.01887, 25.0187, 25.01851, 25.01829, 25.01809, 25.01804, 25.01799, 25.01794, + 25.01789, 25.01784, 25.01779, 25.01759, 25.01743, 25.01724, 25.01714, 25.01716, 25.01719, + 25.01721, 25.01723, 25.01724, 25.01724, 25.01723, 25.01722, 25.01722, 25.01721, 25.0172, + 25.01719, 25.01718, 25.01717, 25.01714, 25.01713, 25.01711, 25.01707, 25.01704, 25.01701, + 25.01697, 25.01694, 25.01691, 25.01687, 25.01684, 25.01681, 25.01677, 25.01674, 25.01671, + 25.01668, 25.01665, 25.01661, 25.0166, 25.01648, 25.01634, 25.01618, 25.01601, 25.01584, + 25.01568, 25.01553, 25.01539, 25.01525, 25.01519, 25.01516, 25.01513, 25.0151, 25.01507, + 25.01504, 25.01501, 25.01489, 25.01475, 25.01464, 25.01451, 25.01437, 25.01427, 25.01421, + 25.01416, 25.01414, 25.01415, 25.01416, 25.01418, 25.01419, 25.0142, 25.01421, 25.01422, + 25.01424, 25.01426, 25.01429, 25.01431, 25.01433, 25.01435, 25.01436, 25.01439, 25.01441, + 25.01445, 25.01448, 25.01452, 25.01456, 25.0146, 25.01463, 25.01466, 25.01469, 25.01472, + 25.01475, 25.01476, 25.01479, 25.01482, 25.01484, 25.01487, 25.0149, 25.01492, 25.01491, + 25.01491, 25.01488, 25.01483, 25.01478, 25.01471, 25.01465, 25.01447, 25.01428, 25.01411, + 25.01395, 25.01377, 25.01358, 25.01338, 25.01317, 25.01299, 25.01281, 25.01264, 25.01244, + 25.01227, 25.01204, 25.01185, 25.01179, 25.01174, 25.01168, 25.01163, 25.01158, 25.01153, + 25.01148, 25.01143, 25.01138, 25.01133, 25.01128, 25.01123, 25.01118, 25.01112, 25.01108, + 25.01103, 25.01098, 25.01093, 25.01089, 25.01084, 25.0108, 25.01074, 25.0107, 25.01065, + 25.0106, 25.01055, 25.01051, 25.01046, 25.01041, 25.01037, 25.01032, 25.01027, 25.01022, + 25.01017, 25.01012, 25.01007, 25.01002, 25.00997, 25.00992, 25.00988, 25.00983, 25.00979, + 25.00974, 25.0097, 25.00965, 25.0096, 25.00956, 25.00951, 25.00947, 25.00941, 25.00936, + 25.00918, 25.009, 25.00882, 25.00871, 25.00865, 25.00862, 25.00861, 25.00859, 25.00857, + 25.00856, 25.00854, 25.00854, 25.00852, 25.00851, 25.0085, 25.00849, 25.00848, 25.00847, + 25.00845, 25.00844, 25.00842, 25.00841, 25.00839, 25.00837, 25.00836, 25.00835, 25.00833, + 25.00831, 25.0083, 25.00828, 25.00827, 25.00825, 25.00824, 25.00823, 25.00822, 25.00821, + 25.0082, 25.00818, 25.00816, 25.00815, 25.00814, 25.00814, 25.00814, 25.00813, 25.00814, + 25.00814, 25.00814, 25.00814, 25.00814, 25.00814, 25.00814, 25.00814, 25.00814, 25.00814, + 25.00814, 25.00815, 25.00815, 25.00815, 25.00815, 25.00814, 25.00814, 25.00813, 25.00813, + 25.00813, 25.00812, 25.00812, 25.00813, 25.00812, 25.00813, 25.00813, 25.00813, 25.00815, + 25.00816, 25.00816, 25.00817, 25.00818, 25.0082, 25.00822, 25.00826, 25.00829, 25.00832, + 25.00835, 25.00838, 25.00852, 25.00854, 25.00856, 25.00862, 25.00865, 25.00867, 25.0087, + 25.00873, 25.00875, 25.00876, 25.00877, 25.00879, 25.00881, 25.00883, 25.00885, 25.00885, + 25.00887, 25.00889, 25.00889, 25.00891, 25.00893, 25.00895, 25.00897, 25.00899, 25.00902, + 25.00905, 25.00907, 25.0091, 25.00914, 25.00917, 25.00918, 25.0092, 25.00922, 25.00923, + 25.00925, 25.00925, 25.00926, 25.00928, 25.00929, 25.0093, 25.00931, 25.00932, 25.00932, + 25.00932, 25.00933, 25.00933, 25.00933, 25.00934, 25.00935, 25.00936, 25.00937, 25.00938, + 25.00939, 25.0094, 25.00941, 25.00942, 25.00943, 25.00947, 25.00949, 25.00955, 25.00963, + 25.00965, 25.00967, 25.0097, 25.00971, 25.00973, 25.00976, 25.00978, 25.0098, 25.00982, + 25.00983, 25.00984, 25.00985, 25.00984, 25.00984, 25.00984, 25.00983, 25.00981, 25.0098, + 25.00978, 25.00977, 25.00977, 25.00976, 25.00976, 25.00977, 25.00978, 25.00978, 25.0098, + 25.00982, 25.00984, 25.00985, 25.00986, 25.00987, 25.00988, 25.00989, 25.0099, 25.00992, + 25.00994, 25.00996, 25.00998, 25.00999, 25.01001, 25.01004, 25.01008, 25.01012, 25.01016, + 25.01021, 25.01024, 25.01028, 25.01032, 25.01036, 25.0104, 25.01044, 25.01047, 25.01051, + 25.01056, 25.01059, 25.01063, 25.0107, 25.01075, 25.01079, 25.01084, 25.01088, 25.01093, + 25.01097, 25.01102, 25.01106, 25.0111, 25.01115, 25.01119, 25.01123, 25.01131, 25.01135, + 25.01139, 25.01144, 25.01147, 25.01152, 25.01156, 25.01161, 25.01166, 25.01171, 25.01177, + 25.01201, 25.01217, 25.01234, 25.01253, 25.01274, 25.01294, 25.013, 25.01306, 25.01311, + 25.01316, 25.01321, 25.01327, 25.01332, 25.01337, 25.01342, 25.01347, 25.01353, 25.01359, + 25.01365, 25.0137, 25.01375, 25.0138, 25.01385, 25.0139, 25.01395, 25.01398, 25.01402, + 25.01405, 25.01409, 25.01413, 25.01417, 25.0142, 25.01423, 25.01427, 25.0143, 25.01434, + 25.01437, 25.01439, 25.01442, 25.01445, 25.01449, 25.01452, 25.01455, 25.01459, 25.01462, + 25.01465, 25.01469, 25.01473, 25.01477, 25.0148, 25.01485, 25.01488, 25.01491, 25.01495, + 25.015, 25.01503, 25.01508, 25.01513, 25.01518, 25.01524, 25.01529, 25.01536, 25.01542, + 25.01548, 25.01554, 25.0156, 25.01566, 25.01572, 25.01577, 25.01582, 25.01588, 25.01593, + 25.01598, 25.01603, 25.01608, 25.01613, 25.01619, 25.01624, 25.01629, 25.01634, 25.01639, + 25.01645, 25.01651, 25.01656, 25.01662, 25.01668, 25.01674, 25.0168, 25.01686, 25.01691, + 25.01697, 25.01702, 25.01707, 25.01713, 25.01718, 25.01723, 25.01729, 25.01734, 25.01738, + 25.01744, 25.01749, 25.01754, 25.01759, 25.01764, 25.01769, 25.01774, 25.01779, 25.01784, + 25.01789, 25.01793, 25.01798, 25.01803, 25.01809, 25.01814, 25.01819, 25.01823, 25.01828, + 25.01832, 25.01836, 25.01851, 25.01855, 25.01859, 25.01864, 25.01868, 25.01873, 25.01878, + 25.01883, 25.01887, 25.01892, 25.01909, 25.01914, 25.01921, 25.01926, 25.01932, 25.01939, + 25.01944, 25.0195, 25.01956, 25.01962, 25.01968, 25.01973, 25.01979, 25.01984, 25.0199, + 25.01997, 25.02002, 25.02008, 25.02013, 25.02017, 25.02022, 25.02027, 25.02032, 25.02038, + 25.02043, 25.02049, 25.02054, 25.0206, 25.02065, 25.0207, 25.02075, 25.0208, 25.02085, + 25.0209, 25.02095, 25.021, 25.02106, 25.02111, 25.02116, 25.02121, 25.02127, 25.02132, + 25.02137, 25.02142, 25.02147, 25.02152, 25.02157, 25.02162, 25.02168, 25.02173, 25.02178, + 25.02183, 25.02188, 25.02193, 25.02199, 25.02203, 25.02208, 25.02213, 25.02217, 25.02221, + 25.02225, 25.0223, 25.02235, 25.02239, 25.02244, 25.02248, 25.02252, 25.02257, 25.02261, + 25.02265, 25.02269, 25.02272, 25.02276, 25.0228, 25.02284, 25.02288, 25.02291, 25.02294, + 25.02298, 25.02302, 25.02305, 25.02309, 25.02313, 25.02316, 25.02319, 25.02322, 25.02326, + 25.02329, 25.02332, 25.02336, 25.0234, 25.02344, 25.02349, 25.02352, 25.02357, 25.02361, + 25.02366, 25.02371, 25.02375, 25.0238, 25.02384, 25.02387, 25.02391, 25.02394, 25.02399, + 25.02404, 25.02409, 25.02415, 25.02419, 25.02423, 25.02427, 25.02432, 25.02436, 25.02441, + 25.02445, 25.02449, 25.02454, 25.02457, 25.02462, 25.02466, 25.0247, 25.02474, 25.02477, + 25.0248, 25.02483, 25.02485, 25.02491, 25.02493, 25.02498, 25.025, 25.02504, 25.02507, + 25.02509, 25.02512, 25.02515, 25.02518, 25.0252, 25.02522, 25.02524, 25.02526, 25.02527, + 25.02528, 25.02529, 25.02531, 25.02532, 25.02533, 25.02535, 25.02536, 25.02537, 25.02538, + 25.02538, 25.02539, 25.02539, 25.02539, 25.0254, 25.02541, 25.02541, 25.02541, 25.02541, + 25.02542, 25.02542, 25.02542, 25.02542, 25.02544, 25.02545, 25.02547, 25.0255, 25.02552, + 25.02554, 25.02556, 25.02558, 25.0256, 25.02564, 25.02569, 25.02576, 25.0258, 25.02584, + 25.02588, 25.02592, 25.02597, 25.02601, 25.02608, 25.02612, 25.02617, 25.02622, 25.02627, + 25.02632, 25.02636, 25.02642, 25.02646, 25.02651, 25.02656, 25.02661, 25.02666, 25.02671, + 25.02675, 25.02678, 25.02682, 25.02686, 25.02689, 25.02693, 25.02697, 25.02701, 25.02704, + 25.0271, 25.02715, 25.02719, 25.02723, 25.02728, 25.02732, 25.02737, 25.02741, 25.02746, + 25.02751, 25.02757, 25.02762, 25.02767, 25.02772, 25.02776, 25.02781, 25.02786, 25.02791, + 25.02795, 25.02799, 25.02804, 25.02808, 25.02812, 25.02816, 25.02821, 25.02826, 25.0283, + 25.02833, 25.02836, 25.02838, 25.0284, 25.02842, 25.02844, 25.02846, 25.02848, 25.02849, + 25.02852, 25.02854, 25.02856, 25.02858, 25.02861, 25.02863, 25.02865, 25.02867, 25.02869, + 25.02871, 25.02873, 25.02875, 25.02877, 25.02879, 25.02881, 25.02883, 25.02885, 25.02888, + 25.0289, 25.02893, 25.02895, 25.02897, 25.029, 25.02902, 25.02904, 25.02907, 25.02909, + 25.02911, 25.02913, 25.02915, 25.02918, 25.0292, 25.02923, 25.02925, 25.02927, 25.0293, + 25.02932, 25.02934, 25.02937, 25.02939, 25.02941, 25.02942, 25.02944, 25.02946, 25.02949, + 25.02951, 25.02953, 25.02955, 25.02957, 25.02959, 25.02961, 25.02964, 25.02966, 25.02968, + 25.02971, 25.02973, 25.02975, 25.02977, 25.02979, 25.02981, 25.02982, 25.02985, 25.02987, + 25.02989, 25.02991, 25.02993, 25.02996, 25.02997, 25.02999, 25.03002, 25.03004, 25.03006, + 25.03008, 25.03011, 25.03013, 25.03016, 25.03018, 25.03021, 25.03023, 25.03025, 25.03027, + 25.03029, 25.03031, 25.03034, 25.03036, 25.03038, 25.0304, 25.03043, 25.03045, 25.03047, + 25.03049, 25.03051, 25.03054, 25.03056, 25.03058, 25.03059, 25.03061, 25.03064, 25.03066, + 25.03068, 25.0307, 25.03071, 25.03073, 25.03076, 25.03078, 25.0308, 25.03082, 25.03084, + 25.03086, 25.03088, 25.03091, 25.03093, 25.03095, 25.03097, 25.03099, 25.03101, 25.03103, + 25.03105, 25.03107, 25.03109, 25.03112, 25.03114, 25.03116, 25.03119, 25.03121, 25.03123, + 25.03126, 25.03128, 25.0313, 25.03132, 25.03134, 25.03136, 25.03138, 25.0314, 25.03142, + 25.03144, 25.03146, 25.03148, 25.0315, 25.03152, 25.03154, 25.03156, 25.03158, 25.03161, + 25.03163, 25.03165, 25.03167, 25.03169, 25.03171, 25.03173, 25.03175, 25.03177, 25.0318, + 25.03182, 25.03184, 25.03186, 25.03188, 25.0319, 25.03192, 25.03194, 25.03196, 25.03198, + 25.032, 25.03202, 25.03205, 25.03207, 25.03209, 25.03211, 25.03213, 25.03216, 25.03218, + 25.0322, 25.03223, 25.03225, 25.03227, 25.03229, 25.03231, 25.03233, 25.03234, 25.03236, + 25.03238, 25.03241, 25.03243, 25.03245, 25.03248, 25.0325, 25.03253, 25.03255, 25.03257, + 25.03259, 25.03261, 25.03263, 25.03265, 25.03268, 25.0327, 25.03272, 25.03274, 25.03276, + 25.03278, 25.03279, 25.03282, 25.03284, 25.03288, 25.03292, 25.03296, 25.03301, 25.03304, + 25.03308, 25.03311, 25.03313, 25.03315, 25.03317, 25.03318, 25.0332, 25.03322, 25.03325, + 25.03329, 25.03332, 25.03337, 25.03341, 25.03346, 25.0335, 25.03355, 25.03359, 25.03364, + 25.03367, 25.03371, 25.03376, 25.03381, 25.03385, 25.0339, 25.03396, 25.034, 25.03405, + 25.03409, 25.03413, 25.03417, 25.0342, 25.03422, 25.03424, 25.03426, 25.03428, 25.03431, + 25.03434, 25.03437, 25.03441, 25.03444, 25.03446, 25.0345, 25.03452, 25.03455, 25.0346, + 25.03464, 25.03468, 25.03472, 25.03477, 25.03482, 25.03487, 25.03496, 25.03502, 25.03511, + 25.03515, 25.03519, 25.03535, 25.03548, 25.03561, 25.03573, 25.03588, 25.03592, 25.03607, + 25.03625, 25.03645, 25.03667, 25.03683, 25.03688, 25.03697, 25.03702, 25.03706, 25.03712, + 25.03716, 25.0372, 25.03724, 25.03728, 25.03739, 25.03743, 25.03746, 25.03753, 25.0377, + 25.03782, 25.03795, 25.0381, 25.03826, 25.03843, 25.0386, 25.03879, 25.03898, 25.03918, + 25.03941, 25.0396, 25.03978, 25.03999, 25.0402, 25.04038, 25.04044, 25.04049, 25.04053, + 25.04057, 25.04068, 25.04072, 25.04077, 25.04081, 25.04085, 25.04091, 25.04096, 25.041, + 25.04103, 25.04106, 25.04112, 25.04116, 25.0412, 25.04125, 25.04131, 25.04135, 25.0414, + 25.04145, 25.0415, 25.04154, 25.04159, 25.04162, 25.04166, 25.04171, 25.04175, 25.04179, + 25.04183, 25.04187, 25.04192, 25.04196, 25.04201, 25.04205, 25.04212, 25.04216, 25.0422, + 25.04227, 25.0423, 25.04235, 25.0424, 25.04245, 25.04249, 25.04253, 25.04256, 25.0426, + 25.04263, 25.04267, 25.0427, 25.04273, 25.04276, 25.0428, 25.04283, 25.04286, 25.04289, + 25.04292, 25.04295, 25.04298, 25.04302, 25.04306, 25.04309, 25.04312, 25.04316, 25.04319, + 25.04322, 25.04326, 25.04329, 25.04333, 25.04348, 25.0435, 25.04353, 25.04356, 25.04359, + 25.04362, 25.04366, 25.04379, 25.04389, 25.04393, 25.04396, 25.04398, 25.04402, 25.04405, + 25.04407, 25.04411, 25.04414, 25.04416, 25.0442, 25.04424, 25.04427, 25.0443, 25.04439, + 25.04448, 25.04453, 25.0446, 25.04466, 25.04471, 25.04489, 25.04495, 25.04499, 25.045, + 25.04502, 25.04504, 25.04506, 25.04507, 25.04508, 25.04509, 25.04511, 25.04512, 25.04513, + 25.04515, 25.04515, 25.04516, 25.04518, 25.04521, 25.04526, 25.04528, 25.0453, 25.04533, + 25.04535, 25.04537, 25.0454, 25.04542, 25.04544, 25.04547, 25.0455, 25.04554, 25.04558, + 25.04561, 25.04565, 25.0457, 25.04575, 25.0458, 25.04585, 25.0459, 25.04595, 25.046, + 25.04606, 25.0461, 25.04615, 25.04621, 25.04626, 25.04632, 25.04637, 25.04642, 25.04654, + 25.04661, 25.04668, 25.04674, 25.0468, 25.04686, 25.04691, 25.04696, 25.04701, 25.04706, + 25.0471, 25.04714, 25.04718, 25.04724, 25.04726, 25.0473, 25.04733, 25.04737, 25.0474, + 25.04743, 25.04747, 25.04751, 25.04755, 25.04759, 25.04763, 25.04767, 25.04769, 25.04771, + 25.04773, 25.04774, 25.04774, 25.04773, 25.0477, 25.04769, 25.04768, 25.04766, 25.04765, + 25.04764, 25.04766, 25.04769, 25.04769, 25.04769, 25.04769, 25.04765, 25.04762, 25.04761, + 25.04761, 25.04761, 25.04762, 25.04764, 25.04767, 25.0477, 25.04773, 25.04776, 25.04778, + 25.0478, 25.04782, 25.04785, 25.04788, 25.04791, 25.04794, 25.04797, 25.048, 25.04802, + 25.04806, 25.04809, 25.04813, 25.04816, 25.0482, 25.04823, 25.04827, 25.0483, 25.04833, + 25.04836, 25.04839, 25.04842, 25.04849, 25.04861, 25.04865, 25.0487, 25.04873, 25.04877, + 25.04881, 25.04888, 25.04891, 25.04893, 25.04895, 25.04897, 25.04899, 25.04898, 25.04896, + 25.04896, 25.04895, 25.04894, 25.04895, 25.04895, 25.04897, 25.04899, 25.049, 25.04901, + 25.04902, 25.04905, 25.04907, 25.0491, 25.04912, 25.04915, 25.04917, 25.0492, 25.04923, + 25.04927, 25.0493, 25.04934, 25.04939, 25.04944, 25.04948, 25.04953, 25.04958, 25.04962, + 25.04966, 25.0497, 25.04974, 25.04978, 25.04982, 25.04985, 25.04988, 25.0499, 25.04993, + 25.04994, 25.04997, 25.04999, 25.05002, 25.05013, 25.0503, 25.05039, 25.05041, 25.05044, + 25.05046, 25.05048, 25.05051, 25.05055, 25.05059, 25.05063, 25.05068, 25.05074, 25.05079, + 25.05085, 25.05091, 25.05096, 25.05101, 25.05105, 25.05109, 25.05113, 25.05117, 25.0512, + 25.05124, 25.05128, 25.05142, 25.05153, 25.05167, 25.0517, 25.05174, 25.05176, 25.05179, + 25.05182, 25.05185, 25.05196, 25.05203, 25.05206, 25.0521, 25.05211, 25.05214, 25.05218, + 25.05222, 25.05224, 25.05228, 25.05243, 25.05255, 25.05261, 25.05262, 25.05265, 25.05267, + 25.05269, 25.05272, 25.05275, 25.05279, 25.05283, 25.05286, 25.05289, 25.05293, 25.05297, + 25.053, 25.05303, 25.05307, 25.05311, 25.05315, 25.05317, 25.0532, 25.05323, 25.05328, + 25.05332, 25.05337, 25.05341, 25.05345, 25.05348, 25.05352, 25.05355, 25.05358, 25.05361, + 25.05364, 25.05368, 25.05372, 25.05375, 25.05377, 25.05381, 25.05383, 25.05386, 25.05388, + 25.05391, 25.05393, 25.05396, 25.05399, 25.05403, 25.05407, 25.05411, 25.05414, 25.05417, + 25.0542, 25.05424, 25.05426, 25.05429, 25.05432, 25.05435, 25.05437, 25.05444, 25.0545, + 25.05454, 25.05456, 25.05461, 25.05464, 25.05468, 25.05471, 25.05481, 25.05485, 25.05489, + 25.05492, 25.05495, 25.05496, 25.05499, 25.05501, 25.05503, 25.05506, 25.05508, 25.05511, + 25.05513, 25.05515, 25.05517, 25.05519, 25.0552, 25.05522, 25.05525, 25.05528, 25.0553, + 25.05531, 25.05532, 25.05534, 25.05536, 25.05538, 25.05541, 25.05543, 25.05546, 25.05548, + 25.05551, 25.05558, 25.05561, 25.05562, 25.05565, 25.05567, 25.0557, 25.05572, 25.05574, + 25.05576, 25.05578, 25.05579, 25.05582, 25.05582, 25.05583, 25.05584, 25.05585, 25.05586, + 25.05587, 25.05587, 25.05587, 25.05588, 25.05587, 25.05585, 25.05584, 25.05582, 25.05581, + 25.05579, 25.05577, 25.05576, 25.05575, 25.05575, 25.05575, 25.05576, 25.05578, 25.05579, + 25.0558, 25.05581, 25.05583, 25.05583, 25.05584, 25.05585, 25.05586, 25.05589, 25.05591, + 25.05593, 25.05596, 25.05599, 25.05603, 25.05605, 25.05608, 25.0561, 25.05614, 25.05619, + 25.05625, 25.0563, 25.05636, 25.05642, 25.05646, 25.05651, 25.05655, 25.0566, 25.05663, + 25.05667, 25.05671, 25.05675, 25.05679, 25.05683, 25.05687, 25.05691, 25.05695, 25.05699, + 25.05703, 25.05707, 25.05712, 25.05716, 25.05719, 25.05723, 25.05727, 25.05731, 25.05735, + 25.05739, 25.05743, 25.05747, 25.05751, 25.05757, 25.05763, 25.05769, 25.05774, 25.05779, + 25.05785, 25.0579, 25.05795, 25.05801, 25.05806, 25.05812, 25.05817, 25.05823, 25.05828, + 25.05834, 25.05839, 25.05844, 25.0585, 25.05855, 25.0586, 25.05866, 25.05871, 25.05876, + 25.05881, 25.05886, 25.0589, 25.05895, 25.059, 25.05905, 25.05911, 25.05917, 25.05922, + 25.05927, 25.05932, 25.05938, 25.05943, 25.05949, 25.05954, 25.0596, 25.05966, 25.05971, + 25.05977, 25.05983, 25.05989, 25.05994, 25.06, 25.06006, 25.06011, 25.06016, 25.06021, + 25.06027, 25.06033, 25.06038, 25.06042, 25.06048, 25.06054, 25.0606, 25.06066, 25.0607, + 25.06075, 25.0608, 25.06084, 25.06088, 25.06093, 25.06099, 25.06105, 25.06109, 25.06115, + 25.0612, 25.06125, 25.06129, 25.06134, 25.06139, 25.06144, 25.06149, 25.06153, 25.06158, + 25.06162, 25.06166, 25.06171, 25.06175, 25.0618, 25.06185, 25.0619, 25.06196, 25.06201, + 25.06206, 25.06211, 25.06215, 25.06219, 25.06224, 25.06228, 25.06232, 25.06237, 25.06242, + 25.06246, 25.06251, 25.06255, 25.06259, 25.06263, 25.06268, 25.06272, 25.06275, 25.06279, + 25.06282, 25.06285, 25.06288, 25.06291, 25.06293, 25.063, 25.06308, 25.06313, 25.06318, + 25.06323, 25.06327, 25.06332, 25.06336, 25.06341, 25.06346, 25.06351, 25.06356, 25.06362, + 25.06367, 25.06373, 25.06377, 25.06382, 25.06387, 25.06392, 25.06397, 25.06403, 25.06408, + 25.06414, 25.06419, 25.06423, 25.06431, 25.06435, 25.0644, 25.06446, 25.06451, 25.06456, + 25.06462, 25.06467, 25.06473, 25.06477, 25.06483, 25.06488, 25.06493, 25.06498, 25.06502, + 25.06507, 25.06512, 25.06516, 25.0652, 25.06525, 25.0653, 25.06535, 25.0654, 25.06546, + 25.0655, 25.06556, 25.06561, 25.06567, 25.06571, 25.06575, 25.0658, 25.06585, 25.06588, + 25.06592, 25.06595, 25.066, 25.06605, 25.0661, 25.06614, 25.06619, 25.06623, 25.06627, + 25.06632, 25.06638, 25.06644, 25.0665, 25.06655, 25.06662, 25.06668, 25.06674, 25.06681, + 25.06688, 25.06695, 25.06702, 25.06709, 25.06715, 25.06721, 25.06728, 25.06734, 25.06741, + 25.06749, 25.06755, 25.06762, 25.06767, 25.06774, 25.06779, 25.06786, 25.06793, 25.06799, + 25.06805, 25.06811, 25.06818, 25.06823, 25.06829, 25.06836, 25.06842, 25.06848, 25.06854, + 25.06861, 25.06868, 25.06874, 25.06881, 25.06888, 25.06896, 25.06903, 25.0691, 25.06916, + 25.06924, 25.06932, 25.0694, 25.06947, 25.06954, 25.06961, 25.06968, 25.06976, 25.06984, + 25.06991, 25.06998, 25.07006, 25.07014, 25.07022, 25.0703, 25.07037, 25.07044, 25.07052, + 25.07059, 25.07066, 25.07072, 25.07079, 25.07084, 25.07089, 25.07095, 25.07101, 25.07107, + 25.07112, 25.07119, 25.07126, 25.07132, 25.07138, 25.07144, 25.07151, 25.07158, 25.07165, + 25.07171, 25.07177, 25.07185, 25.07192, 25.07199, 25.07206, 25.07212, 25.07218, 25.07224, + 25.07228, 25.07234, 25.0724, 25.07246, 25.07253, 25.07259, 25.07265, 25.0727, 25.07277, + 25.07283, 25.07288, 25.07294, 25.073, 25.07304, 25.07309, 25.07314, 25.07319, 25.07323, + 25.07328, 25.07331, 25.07337, 25.07342, 25.07346, 25.0735, 25.07353, 25.07357, 25.07361, + 25.07366, 25.07371, 25.07374, 25.07377, 25.07379, 25.07382, 25.07385, 25.07387, 25.07391, + 25.07394, 25.07397, 25.074, 25.07402, 25.07404, 25.07407, 25.0741, 25.07412, 25.07414, + 25.07415, 25.07417, 25.07421, 25.07425, 25.07428, 25.07431, 25.07434, 25.07436, 25.07439, + 25.07442, 25.07446, 25.07449, 25.07453, 25.07457, 25.0746, 25.07463, 25.07466, 25.07469, + 25.07472, 25.07475, 25.07478, 25.07481, 25.07484, 25.07487, 25.0749, 25.07493, 25.07496, + 25.075)
\ No newline at end of file diff --git a/mapbox/src/main/java/com/example/mapbox/ui/MapboxMapView.kt b/mapbox/src/main/java/com/example/mapbox/ui/MapboxMapView.kt new file mode 100644 index 0000000000..04fe3828cc --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/ui/MapboxMapView.kt @@ -0,0 +1,282 @@ +package com.example.mapbox.ui + +import android.annotation.SuppressLint +import android.content.Context +import android.content.res.Resources +import android.location.Location +import android.view.Gravity +import android.view.MotionEvent +import android.view.View +import com.example.mapbox.R +import com.example.mapbox.breadcrumb.ExerciseEngineState +import com.example.mapbox.extensions.getBitmapFromDrawable +import com.example.mapbox.extensions.latLong +import com.mapbox.mapboxsdk.camera.CameraPosition +import com.mapbox.mapboxsdk.camera.CameraUpdateFactory +import com.mapbox.mapboxsdk.geometry.LatLng +import com.mapbox.mapboxsdk.location.LocationComponentOptions +import com.mapbox.mapboxsdk.location.OnCameraTrackingChangedListener +import com.mapbox.mapboxsdk.location.OnLocationCameraTransitionListener +import com.mapbox.mapboxsdk.location.OnLocationStaleListener +import com.mapbox.mapboxsdk.location.modes.CameraMode +import com.mapbox.mapboxsdk.location.modes.RenderMode +import com.mapbox.mapboxsdk.maps.* +import com.soy.android.maps.breadcrumb.Breadcrumb +import com.soy.android.maps.compass.WassCompassEngine +import com.soy.android.maps.extensions.getActivatedLocationComponent +import com.soy.android.maps.extensions.isCameraInTrackingMode +import timber.log.Timber +import kotlin.math.roundToInt + +internal const val INITIAL_CAMERA_ZOOM_LEVEL_INDEX_WITH_LOCATION = 14 +/** + * Map is centered at Helsinki when we don't have user's current or any last location + */ +private const val DEFAULT_INITIAL_CAMERA_POSITION_LATITUDE = 60.1699 +private const val DEFAULT_INITIAL_CAMERA_POSITION_LONGITUDE = 24.9384 + +private const val CAMERA_ANIMATION_DURATION = 200L + +internal fun buildCameraPosition( + target: LatLng = LatLng(DEFAULT_INITIAL_CAMERA_POSITION_LATITUDE, DEFAULT_INITIAL_CAMERA_POSITION_LONGITUDE), + zoomIndex: Int = INITIAL_CAMERA_ZOOM_LEVEL_INDEX_WITH_LOCATION +) = CameraPosition.Builder().target(target).zoom(zoomIndex.toDouble()).build() + +/** + * [MapboxMapOptions] can either be applied via xml or programmatically when [MapView] is + * constructed. This function provides a predefined set of options. + */ +private fun createMapboxMapOptions(resources: Resources, location: Location?): MapboxMapOptions { + val cameraPosition = if (location == null) { + // Use default location and zoom level + buildCameraPosition() + } else { + buildCameraPosition(LatLng(location.latitude, location.longitude), INITIAL_CAMERA_ZOOM_LEVEL_INDEX_WITH_LOCATION) + } + return MapboxMapOptions().apply { + val compassImageTopMargin = resources.getDimension(R.dimen.size_spacing_xxsmall).roundToInt() + compassMargins(intArrayOf(0, compassImageTopMargin, 0, 0)) + compassEnabled(true) + compassImage(resources.getDrawable(R.drawable.ic_shape_north_indicator, null)) + compassGravity(Gravity.CENTER) + textureMode(true) + attributionEnabled(false) + logoEnabled(false) + zoomGesturesEnabled(true) + compassFadesWhenFacingNorth(false) + rotateGesturesEnabled(false) + camera(cameraPosition) + } +} + +internal const val START_SYMBOL_ICON_ID = "id-start-icon" +internal const val PAUSE_LINE_PATTERN = "id-stale-line-pattern" + +/** + * This class extends [MapView] and is suggested to use when creating map programmatically with a + * given cameraPosition which is used to center the camera on map. This view doesn't allow touch + * interactions for the child views of [MapView] such as compass, logo, attribute. + */ +@SuppressLint("ViewConstructor") +class MapboxMapView( + context: Context, + location: Location? = null, + private val isBreadcrumbEnabled: Boolean = true +) : MapView(context, createMapboxMapOptions(context.resources, location)), OnLocationStaleListener, + OnCameraTrackingChangedListener, MapboxMap.OnMapClickListener, OnMapReadyCallback, MapboxMap.OnMapLongClickListener { + + init { + id = View.generateViewId() + } + + private var map: MapboxMap? = null + + private var breadcrumb: Breadcrumb? = null + + private var exerciseEngineState = ExerciseEngineState.Recording + + /** + * A boolean which keeps track of location stale status. Initially location is assigned to be stale since there is + * no gps fix at start up. The value changes in two places: + * 1- When [onStaleStateChange] is invoked, the value is updated based on the parameter + * 2- Whenever there is new gps fix it is set to be false + */ + private var isLocationStale = true + + internal var compassEngine: WassCompassEngine? = null + @CameraMode.Mode + private var lastCameraTrackingMode = CameraMode.TRACKING_COMPASS + private var cameraZoomLevelIndex = INITIAL_CAMERA_ZOOM_LEVEL_INDEX_WITH_LOCATION + private var isDefaultCameraPositionInUse = false + + override fun onMapReady(mapboxMap: MapboxMap) { + map = mapboxMap.apply { + setStyle(Style.Builder() + .withImage(START_SYMBOL_ICON_ID, resources.getBitmapFromDrawable(R.drawable.ic_map_start_pin)) + .withImage(PAUSE_LINE_PATTERN, resources.getBitmapFromDrawable(R.drawable.ic_stale_track_dot)) + .fromUrl(context.getString(R.string.asoy_mapbox_style)) + ) { style -> + startLocationComponent(mapboxMap, style) + if (isBreadcrumbEnabled) { + breadcrumb = Breadcrumb(this@MapboxMapView, mapboxMap, style) + } + } + addOnMapLongClickListener(this@MapboxMapView) + addOnMapClickListener(this@MapboxMapView) + } + } + + // Location + @SuppressLint("MissingPermission") + private fun startLocationComponent(mapboxMap: MapboxMap, style: Style) { + mapboxMap.locationComponent.apply { + // Activate with options. If location engine is null, push location updates to + // the component without any internal engine management. No engine is going to + // be initialized and you can push location updates with + // [LocationComponent#forceLocationUpdate(Location)]. + activateLocationComponent( + context, + style, + null, + LocationComponentOptions.createFromAttributes(context, R.style.mapbox_location) + ) + compassEngine = this@MapboxMapView.compassEngine + addOnCameraTrackingChangedListener(this@MapboxMapView) + isLocationComponentEnabled = true + Timber.d("Mapbox Location Component is enabled") + addOnLocationStaleListener(this@MapboxMapView) + renderMode = RenderMode.GPS + cameraMode = lastCameraTrackingMode + } + } + + internal fun onNewLocation(location: Location) { + isLocationStale = false + map?.run { + getActivatedLocationComponent()?.run { + if (isDefaultCameraPositionInUse) { + updateMapCameraZoom(INITIAL_CAMERA_ZOOM_LEVEL_INDEX_WITH_LOCATION) + isDefaultCameraPositionInUse = false + } + forceLocationUpdate(location) + breadcrumb?.onNewLocation(location.latLong(), exerciseEngineState) + } + } + } + + override fun onStaleStateChange(isStale: Boolean) { + Timber.d("Location stale state change. Is Stale: $isStale") + isLocationStale = isStale + map?.getActivatedLocationComponent()?.run { + renderMode = if (isStale) RenderMode.NORMAL else RenderMode.GPS + val locationComponentStyle = if (isStale) R.style.mapbox_stale_location else R.style.mapbox_location + applyStyle(LocationComponentOptions.createFromAttributes(context, locationComponentStyle)) + } + } + + // Camera + private fun updateMapCameraZoom(zoomLevelIndex: Int) = map?.getActivatedLocationComponent()?.run { + cameraZoomLevelIndex = zoomLevelIndex + if (cameraMode != CameraMode.NONE) { + zoomWhileTracking(getCameraZoomLevel(), CAMERA_ANIMATION_DURATION) + } else { + map?.easeCamera(CameraUpdateFactory.zoomTo(getCameraZoomLevel())) + } + } + + private fun getCameraZoomLevel(): Double = map?.cameraPosition?.zoom ?: 0.0 + + override fun onCameraTrackingChanged(currentMode: Int) { + Timber.d("Camera tracking mode changed. Current mode: $currentMode") + if (map?.isCameraInTrackingMode() == true) { + lastCameraTrackingMode = currentMode + } + } + + /** + * Invoked whenever camera tracking is broken. + */ + override fun onCameraTrackingDismissed() { + Timber.d("Exiting from camera tracking mode") + updateCameraMode(CameraMode.NONE_COMPASS) + } + + private fun updateCameraMode(@CameraMode.Mode mode: Int) { + // We need to + map?.getActivatedLocationComponent()?.apply { + if (cameraMode != CameraMode.NONE) { + setCameraMode(mode, object : OnLocationCameraTransitionListener { + override fun onLocationCameraTransitionFinished(cameraMode: Int) { + zoomWhileTracking(getCameraZoomLevel(), CAMERA_ANIMATION_DURATION) + } + + override fun onLocationCameraTransitionCanceled(cameraMode: Int) { + // No impl. + } + }) + } else { + cameraMode = mode + } + } + } + + // Gestures + /** + * When [MapboxMap.OnMapClickListener.onMapClick] is called camera mode is updated: + * There are two camera tracking modes enabled: + * The [CameraMode.TRACKING_GPS_NORTH] sets the camera always to the north and the [CameraMode.TRACKING_COMPASS] + * sets the location indicator to north and map rotates according to heading + * If camera mode is [CameraMode.TRACKING_GPS_NORTH], onClick switches the mode to [CameraMode.TRACKING_COMPASS] + * If camera mode is [CameraMode.TRACKING_COMPASS] onClick switches the mode to [CameraMode.TRACKING_GPS_NORTH] + * If user starts panning while in tracking mode, camera switches to [CameraMode.NONE_COMPASS] mode and user is not + * tracked by camera. On click switches the camera back to last used tracking mode + */ + override fun onMapClick(point: LatLng): Boolean { + map?.getActivatedLocationComponent()?.apply { + when (cameraMode) { + CameraMode.TRACKING_GPS_NORTH -> updateCameraMode(CameraMode.TRACKING_COMPASS) + CameraMode.TRACKING_COMPASS -> updateCameraMode(CameraMode.TRACKING_GPS_NORTH) + CameraMode.NONE_COMPASS, + CameraMode.NONE, + CameraMode.NONE_GPS -> updateCameraMode(lastCameraTrackingMode) + else -> Timber.w("Using unsupported camera mode") + } + } + return true + } + + /** + * Used for mocking exercise pause / resmume controls + */ + override fun onMapLongClick(point: LatLng): Boolean { + if (exerciseEngineState == ExerciseEngineState.Paused) { + exerciseEngineState = ExerciseEngineState.Recording + } else if (exerciseEngineState == ExerciseEngineState.Recording) { + exerciseEngineState = ExerciseEngineState.Paused + } + return true + } + + /** + * By overriding this method, we prevent compass view component of the [MapView] from consuming the clicks + */ + override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { + super.onInterceptTouchEvent(ev) + return true + } + + override fun onResume() { + super.onResume() + breadcrumb?.onResume() + } + + override fun onStop() { + breadcrumb?.onStop() + super.onStop() + } + + override fun onDestroy() { + breadcrumb?.onDestroy() + super.onDestroy() + } +} diff --git a/mapbox/src/main/java/com/example/mapbox/ui/extensions/ConstraintLayoutExtensions.kt b/mapbox/src/main/java/com/example/mapbox/ui/extensions/ConstraintLayoutExtensions.kt new file mode 100644 index 0000000000..84fa569e1b --- /dev/null +++ b/mapbox/src/main/java/com/example/mapbox/ui/extensions/ConstraintLayoutExtensions.kt @@ -0,0 +1,19 @@ +package com.example.mapbox.ui.extensions + +import android.support.constraint.ConstraintLayout +import android.support.constraint.ConstraintSet +import android.view.View + +fun ConstraintLayout.addViewAndMatchItToParent(view: View, zIndex: Int = 0) { + addView(view, zIndex) + ConstraintSet().run { + clone(this@addViewAndMatchItToParent) + view.run { + connect(id, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP) + connect(id, ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START) + connect(id, ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END) + connect(id, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM) + } + applyTo(this@addViewAndMatchItToParent) + } +} |