Skip to content

Commit

Permalink
Merge branch 'navigation-mode'
Browse files Browse the repository at this point in the history
  • Loading branch information
westnordost committed Oct 2, 2021
2 parents e9f5f81 + 6064c1c commit 6490c40
Show file tree
Hide file tree
Showing 27 changed files with 444 additions and 225 deletions.
47 changes: 47 additions & 0 deletions app/src/main/assets/map_theme/jawg/streetcomplete.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
global:
geometry_color: '#44D14000' # accent color + alpha
track_color: '#44536dfe'
old_track_color: '#22536dfe'

textures:
pins:
Expand Down Expand Up @@ -40,6 +42,9 @@ styles:
geometry-points:
base: points
blend: overlay
track-lines:
base: lines
blend: overlay

layers:
streetcomplete_selected_pins:
Expand Down Expand Up @@ -114,3 +119,45 @@ layers:
size: 32px
collide: false
order: 1000
# streetcomplete_track and streetcomplete_track2 layers are exactly the same except the source.
# It is not possible in tangram to define a layer for several sources.
streetcomplete_track:
data: { source: streetcomplete_track }
current:
filter: { old: [false] }
draw:
track-lines:
color: global.track_color
width: [[14, 6px],[18, 12px]]
collide: false
join: round
order: 1000
old:
filter: { old: [true] }
draw:
track-lines:
color: global.old_track_color
width: [[14, 6px],[18, 12px]]
collide: false
join: round
order: 1000
streetcomplete_track2:
data: { source: streetcomplete_track2 }
current:
filter: { old: [false] }
draw:
track-lines:
color: global.track_color
width: [[14, 6px],[18, 12px]]
collide: false
join: round
order: 1000
old:
filter: { old: [true] }
draw:
track-lines:
color: global.old_track_color
width: [[14, 6px],[18, 12px]]
collide: false
join: round
order: 1000
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class FineLocationManager(private val mgr: LocationManager, private var location

// taken from https://developer.android.com/guide/topics/location/strategies.html#kotlin

private const val TWO_MINUTES: Long = 1000 * 60 * 2
private const val TWO_MINUTES = 1000L * 60 * 2

/** Determines whether one Location reading is better than the current Location fix
* @param location The new Location that you want to evaluate
Expand All @@ -74,19 +74,19 @@ private fun isBetterLocation(location: Location, currentBestLocation: Location?)
}

// Check whether the new location fix is newer or older
val timeDelta: Long = location.time - currentBestLocation.time
val isSignificantlyNewer: Boolean = timeDelta > TWO_MINUTES
val isSignificantlyOlder:Boolean = timeDelta < -TWO_MINUTES
val isNewer: Boolean = timeDelta > 0L
val timeDelta = location.time - currentBestLocation.time
val isSignificantlyNewer = timeDelta > TWO_MINUTES
val isSignificantlyOlder = timeDelta < -TWO_MINUTES
val isNewer = timeDelta > 0L

// Check whether the new location fix is more or less accurate
val accuracyDelta: Float = location.accuracy - currentBestLocation.accuracy
val isLessAccurate: Boolean = accuracyDelta > 0f
val isMoreAccurate: Boolean = accuracyDelta < 0f
val isSignificantlyLessAccurate: Boolean = accuracyDelta > 200f
val accuracyDelta = location.accuracy - currentBestLocation.accuracy
val isLessAccurate = accuracyDelta > 0f
val isMoreAccurate = accuracyDelta < 0f
val isSignificantlyLessAccurate = accuracyDelta > 200f

// Check if the old and new location are from the same provider
val isFromSameProvider: Boolean = location.provider == currentBestLocation.provider
val isFromSameProvider = location.provider == currentBestLocation.provider

// Determine location quality using a combination of timeliness and accuracy
return when {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ enum class LocationState {

// receiving location updates
val isEnabled: Boolean get() = ordinal >= ENABLED.ordinal
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import android.view.View
import androidx.annotation.Keep
import androidx.appcompat.widget.AppCompatImageButton
import de.westnordost.streetcomplete.R
import java.util.Arrays
import de.westnordost.streetcomplete.location.LocationState.*

/**
* An image button which shows the current location state
Expand All @@ -23,37 +23,44 @@ class LocationStateButton @JvmOverloads constructor(
) : AppCompatImageButton(context, attrs, defStyle) {

var state: LocationState
get() = _state ?: LocationState.DENIED
get() = _state ?: DENIED
set(value) { _state = value }

// this is necessary because state is accessed before it is initialized (in contructor of super)
// this is necessary because state is accessed before it is initialized (in constructor of super)
private var _state: LocationState? = null
set(value) {
if (field != value) {
field = value
refreshDrawableState()
}
}

private val tint: ColorStateList?

var isNavigation: Boolean = false
set(value) {
if (field != value) {
field = value
refreshDrawableState()
}
}


init {
val a = context.obtainStyledAttributes(attrs, R.styleable.LocationStateButton)
state = determineStateFrom(a)
tint = a.getColorStateList(R.styleable.LocationStateButton_tint)
isNavigation = a.getBoolean(R.styleable.LocationStateButton_is_navigation, false)

a.recycle()
}

private fun determineStateFrom(a: TypedArray): LocationState {
if (a.getBoolean(R.styleable.LocationStateButton_state_updating,false))
return LocationState.UPDATING
if (a.getBoolean(R.styleable.LocationStateButton_state_searching,false))
return LocationState.SEARCHING
if (a.getBoolean(R.styleable.LocationStateButton_state_enabled,false))
return LocationState.ENABLED
if (a.getBoolean(R.styleable.LocationStateButton_state_allowed,false))
return LocationState.ALLOWED
else
return LocationState.DENIED
private fun determineStateFrom(a: TypedArray): LocationState = when {
a.getBoolean(R.styleable.LocationStateButton_state_updating,false) -> UPDATING
a.getBoolean(R.styleable.LocationStateButton_state_searching,false) -> SEARCHING
a.getBoolean(R.styleable.LocationStateButton_state_enabled,false) -> ENABLED
a.getBoolean(R.styleable.LocationStateButton_state_allowed,false) -> ALLOWED
else -> DENIED
}

override fun drawableStateChanged() {
Expand All @@ -69,19 +76,22 @@ class LocationStateButton @JvmOverloads constructor(
}

override fun onCreateDrawableState(extraSpace: Int): IntArray {
val additionalLength = STATES.size + 1
val drawableState = super.onCreateDrawableState(extraSpace + additionalLength)
val arrPos = state.ordinal
val additionalArray = Arrays.copyOf(Arrays.copyOf(STATES, arrPos), additionalLength)
View.mergeDrawableStates(drawableState, additionalArray)
val attributes = ArrayList<Int>()
attributes += state.styleableAttributes
if (isNavigation) attributes += R.attr.is_navigation

val drawableState = super.onCreateDrawableState(extraSpace + attributes.size)

View.mergeDrawableStates(drawableState, attributes.toIntArray())
return drawableState
}

public override fun onSaveInstanceState(): Parcelable? {
public override fun onSaveInstanceState(): Parcelable {
val superState = super.onSaveInstanceState()
val ss = SavedState(superState)
ss.state = state
ss.activated = isActivated
ss.navigation = isNavigation
return ss
}

Expand All @@ -90,23 +100,27 @@ class LocationStateButton @JvmOverloads constructor(
super.onRestoreInstanceState(ss.superState)
state = ss.state
isActivated = ss.activated
isNavigation = ss.navigation
requestLayout()
}

internal class SavedState : BaseSavedState {
var state: LocationState = LocationState.DENIED
var state: LocationState = DENIED
var activated = false
var navigation = false

constructor(superState: Parcelable?) : super(superState)
constructor(parcel: Parcel) : super(parcel) {
state = LocationState.valueOf(parcel.readString()!!)
activated = parcel.readInt() == 1
navigation = parcel.readInt() == 1
}

override fun writeToParcel(out: Parcel, flags: Int) {
super.writeToParcel(out, flags)
out.writeString(state.name)
out.writeInt(if (activated) 1 else 0)
out.writeInt(if (navigation) 1 else 0)
}

companion object {
Expand All @@ -117,14 +131,12 @@ class LocationStateButton @JvmOverloads constructor(
}
}
}

companion object {
// must be defined in the same order as the LocationState enum (but minus the first)
private val STATES = intArrayOf(
R.attr.state_allowed,
R.attr.state_enabled,
R.attr.state_searching,
R.attr.state_updating
)
}
}

private val LocationState.styleableAttributes: List<Int> get() =
listOf(
R.attr.state_allowed,
R.attr.state_enabled,
R.attr.state_searching,
R.attr.state_updating
).subList(0, ordinal)
15 changes: 15 additions & 0 deletions app/src/main/java/de/westnordost/streetcomplete/map/Bearing.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package de.westnordost.streetcomplete.map

import android.location.Location

/** Utility functions to estimate current bearing from a track. This is necessary because
* Location.bearingAccuracy doesn't exist on Android versions below Android API 26, otherwise
* a solution based on this would be less code. E.g. take bearing if accuracy < X */

fun getTrackBearing(track: List<Location>): Float? {
val last = track.lastOrNull() ?: return null
val point = track.findLast { it.distanceTo(last) > MIN_TRACK_DISTANCE_FOR_BEARING } ?: return null
return point.bearingTo(last)
}

private const val MIN_TRACK_DISTANCE_FOR_BEARING = 15f // 15 meters
Loading

0 comments on commit 6490c40

Please sign in to comment.