Skip to content

Commit

Permalink
Add haptic feedback (Kr0oked#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kr0oked authored Apr 9, 2023
1 parent c1dfd62 commit 7dfa266
Show file tree
Hide file tree
Showing 25 changed files with 213 additions and 4 deletions.
1 change: 1 addition & 0 deletions app/src/main/java/com/bobek/compass/CompassFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class CompassFragment : Fragment() {
private fun initPreferenceStore() {
preferenceStore = PreferenceStore(requireContext(), lifecycle)
preferenceStore.trueNorth.observe(viewLifecycleOwner) { compassViewModel.trueNorth.value = it }
preferenceStore.hapticFeedback.observe(viewLifecycleOwner) { compassViewModel.hapticFeedback.value = it }
}

private fun setupSystemServices() {
Expand Down
10 changes: 7 additions & 3 deletions app/src/main/java/com/bobek/compass/model/Azimuth.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* This file is part of Compass.
* Copyright (C) 2022 Philipp Bobek <philipp.bobek@mailbox.org>
* Copyright (C) 2023 Philipp Bobek <philipp.bobek@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand All @@ -20,8 +20,6 @@ package com.bobek.compass.model

class Azimuth(_degrees: Float) {

operator fun plus(degrees: Float) = Azimuth(this.degrees + degrees)

val degrees = normalizeAngle(_degrees)

val cardinalDirection: CardinalDirection = when (degrees) {
Expand Down Expand Up @@ -57,6 +55,12 @@ class Azimuth(_degrees: Float) {
override fun toString(): String {
return "Azimuth(degrees=$degrees)"
}

operator fun plus(degrees: Float) = Azimuth(this.degrees + degrees)

operator fun minus(degrees: Float) = Azimuth(this.degrees - degrees)

operator fun compareTo(azimuth: Azimuth) = this.degrees.compareTo(azimuth.degrees)
}

private data class SemiClosedFloatRange(val fromInclusive: Float, val toExclusive: Float)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ object PreferenceConstants {

const val TRUE_NORTH = "true_north"

const val HAPTIC_FEEDBACK = "haptic_feedback"

const val SCREEN_ORIENTATION_LOCKED = "screen_orientation_locked"

const val NIGHT_MODE = "night_mode"
Expand Down
20 changes: 20 additions & 0 deletions app/src/main/java/com/bobek/compass/preference/PreferenceStore.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ private const val TAG = "PreferenceStore"
class PreferenceStore(context: Context, lifecycle: Lifecycle) {

val trueNorth = MutableLiveData<Boolean>()
val hapticFeedback = MutableLiveData<Boolean>()
val screenOrientationLocked = MutableLiveData<Boolean>()
val nightMode = MutableLiveData<AppNightMode>()
val accessCoarseLocationPermissionRequested = MutableLiveData<Boolean>()
Expand All @@ -42,6 +43,7 @@ class PreferenceStore(context: Context, lifecycle: Lifecycle) {
private val sharedPreferenceChangeListener = SharedPreferenceChangeListener()

private val trueNorthObserver = getTrueNorthObserver()
private val hapticFeedbackObserver = getHapticFeedbackObserver()
private val screenOrientationLockedObserver = getScreenOrientationLockedObserver()
private val nightModeObserver = getNightModeObserver()
private val accessCoarseLocationPermissionRequestedObserver = getAccessCoarseLocationPermissionRequestedObserver()
Expand All @@ -52,6 +54,7 @@ class PreferenceStore(context: Context, lifecycle: Lifecycle) {
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)

updateTrueNorth()
updateHapticFeedback()
updateScreenOrientationLocked()
updateNightMode()
updateAccessCoarseLocationPermissionRequested()
Expand All @@ -63,6 +66,7 @@ class PreferenceStore(context: Context, lifecycle: Lifecycle) {

override fun onCreate(owner: LifecycleOwner) {
trueNorth.observeForever(trueNorthObserver)
hapticFeedback.observeForever(hapticFeedbackObserver)
screenOrientationLocked.observeForever(screenOrientationLockedObserver)
nightMode.observeForever(nightModeObserver)
accessCoarseLocationPermissionRequested.observeForever(accessCoarseLocationPermissionRequestedObserver)
Expand All @@ -74,6 +78,7 @@ class PreferenceStore(context: Context, lifecycle: Lifecycle) {
sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)

trueNorth.removeObserver(trueNorthObserver)
hapticFeedback.removeObserver(hapticFeedbackObserver)
screenOrientationLocked.removeObserver(screenOrientationLockedObserver)
nightMode.removeObserver(nightModeObserver)
accessCoarseLocationPermissionRequested.removeObserver(accessCoarseLocationPermissionRequestedObserver)
Expand All @@ -84,6 +89,7 @@ class PreferenceStore(context: Context, lifecycle: Lifecycle) {
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) {
when (key) {
PreferenceConstants.TRUE_NORTH -> updateTrueNorth()
PreferenceConstants.HAPTIC_FEEDBACK -> updateHapticFeedback()
PreferenceConstants.SCREEN_ORIENTATION_LOCKED -> updateScreenOrientationLocked()
PreferenceConstants.NIGHT_MODE -> updateNightMode()
PreferenceConstants.ACCESS_COARSE_LOCATION_PERMISSION_REQUESTED -> {
Expand All @@ -100,6 +106,13 @@ class PreferenceStore(context: Context, lifecycle: Lifecycle) {
}
}

private fun updateHapticFeedback() {
val storedValue = sharedPreferences.getBoolean(PreferenceConstants.HAPTIC_FEEDBACK, true)
if (hapticFeedback.value != storedValue) {
hapticFeedback.value = storedValue
}
}

private fun updateScreenOrientationLocked() {
val storedValue = sharedPreferences.getBoolean(PreferenceConstants.SCREEN_ORIENTATION_LOCKED, false)
if (screenOrientationLocked.value != storedValue) {
Expand Down Expand Up @@ -133,6 +146,13 @@ class PreferenceStore(context: Context, lifecycle: Lifecycle) {
Log.d(TAG, "Persisted trueNorth: $it")
}

private fun getHapticFeedbackObserver(): (t: Boolean) -> Unit = {
val edit = sharedPreferences.edit()
edit.putBoolean(PreferenceConstants.HAPTIC_FEEDBACK, it)
edit.apply()
Log.d(TAG, "Persisted hapticFeedback: $it")
}

private fun getScreenOrientationLockedObserver(): (t: Boolean) -> Unit = {
val edit = sharedPreferences.edit()
edit.putBoolean(PreferenceConstants.SCREEN_ORIENTATION_LOCKED, it)
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/com/bobek/compass/util/MathUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import com.bobek.compass.model.Azimuth
import com.bobek.compass.model.DisplayRotation
import com.bobek.compass.model.DisplayRotation.*
import com.bobek.compass.model.RotationVector
import kotlin.math.roundToInt

private const val AZIMUTH = 0
private const val AXIS_SIZE = 3
Expand Down Expand Up @@ -72,4 +73,7 @@ object MathUtils {
val geomagneticField = GeomagneticField(latitude, longitude, altitude, time)
return geomagneticField.declination
}

fun getClosestNumberFromInterval(number: Float, interval: Float): Float =
(number / interval).roundToInt() * interval
}
35 changes: 35 additions & 0 deletions app/src/main/java/com/bobek/compass/view/CompassView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import android.content.Context
import android.util.AttributeSet
import android.util.TypedValue
import android.util.TypedValue.COMPLEX_UNIT_PX
import android.view.HapticFeedbackConstants
import android.view.LayoutInflater
import androidx.annotation.AnyRes
import androidx.annotation.IdRes
Expand All @@ -30,13 +31,18 @@ import androidx.constraintlayout.widget.ConstraintSet
import com.bobek.compass.R
import com.bobek.compass.databinding.CompassViewBinding
import com.bobek.compass.model.Azimuth
import com.bobek.compass.util.MathUtils
import kotlin.math.roundToInt

private const val HAPTIC_FEEDBACK_INTERVAL = 2.0f

class CompassView(context: Context, attributes: AttributeSet) : ConstraintLayout(context, attributes) {

@IdRes
private val center = R.id.compass_rose_image

private var lastHapticFeedbackPoint: Azimuth? = null

private var binding: CompassViewBinding

init {
Expand Down Expand Up @@ -90,6 +96,7 @@ class CompassView(context: Context, attributes: AttributeSet) : ConstraintLayout
val rotation = azimuth.degrees.unaryMinus()
rotateCompassRoseImage(rotation)
rotateCompassRoseTexts(rotation)
handleHapticFeedback(azimuth)

visibility = VISIBLE
}
Expand Down Expand Up @@ -151,4 +158,32 @@ class CompassView(context: Context, attributes: AttributeSet) : ConstraintLayout
private fun calculateTextRadius(ratio: Float): Int {
return width / 2 - (width * ratio).toInt()
}

private fun handleHapticFeedback(azimuth: Azimuth) {
lastHapticFeedbackPoint
?.also { checkHapticFeedback(azimuth, it) }
?: run { initializeLastHapticFeedbackPoint(azimuth) }
}

private fun checkHapticFeedback(azimuth: Azimuth, lastHapticFeedbackkPoint: Azimuth) {
val boundaryStart = lastHapticFeedbackkPoint - HAPTIC_FEEDBACK_INTERVAL
val boundaryEnd = lastHapticFeedbackkPoint + HAPTIC_FEEDBACK_INTERVAL

if (azimuth < boundaryStart) {
this.lastHapticFeedbackPoint = boundaryStart
performHapticFeedback()
} else if (azimuth > boundaryEnd) {
this.lastHapticFeedbackPoint = boundaryEnd
performHapticFeedback()
}
}

private fun performHapticFeedback() {
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
}

private fun initializeLastHapticFeedbackPoint(azimuth: Azimuth) {
val closestIntervalPoint = MathUtils.getClosestNumberFromInterval(azimuth.degrees, HAPTIC_FEEDBACK_INTERVAL)
lastHapticFeedbackPoint = Azimuth(closestIntervalPoint)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class CompassViewModel : ViewModel() {

val sensorAccuracy = MutableLiveData(SensorAccuracy.NO_CONTACT)
val trueNorth = MutableLiveData(false)
val hapticFeedback = MutableLiveData(true)
val accessCoarseLocationPermissionGranted = MutableLiveData(false)
val location = MutableLiveData<Location>()
}
1 change: 1 addition & 0 deletions app/src/main/res/layout-land/fragment_compass.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
android:id="@+id/compass"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:hapticFeedbackEnabled="@{model.hapticFeedback}"
android:keepScreenOn="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/fragment_compass.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
android:id="@+id/compass"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hapticFeedbackEnabled="@{model.hapticFeedback}"
android:keepScreenOn="true"
app:layout_constraintBottom_toTopOf="@id/location_container"
app:layout_constraintEnd_toEndOf="parent"
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values-bs/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
<!--TODO<string name="true_north">True North</string>-->
<!--TODO<string name="true_north_summary">Correct the magnetic declination and show to true north. Requires access to your coarse location.</string>-->

<!--TODO<string name="haptic_feedback">Haptic feedback</string>-->
<!--TODO<string name="haptic_feedback_summary">The compass vibrates when the direction changes.</string>-->

<!--TODO<string name="display">Display</string>-->
<!--TODO<string name="night_mode">Night mode</string>-->
<!--TODO<string name="night_mode_follow_system">System</string>-->
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values-cs/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
<!--TODO<string name="true_north">True North</string>-->
<!--TODO<string name="true_north_summary">Correct the magnetic declination and show to true north. Requires access to your coarse location.</string>-->

<!--TODO<string name="haptic_feedback">Haptic feedback</string>-->
<!--TODO<string name="haptic_feedback_summary">The compass vibrates when the direction changes.</string>-->

<string name="display">Ukázat</string>
<string name="night_mode">Noční režim</string>
<string name="night_mode_follow_system">Systém</string>
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
<string name="true_north">Geografischer Norden</string>
<string name="true_north_summary">Die magnetische Deklination wird korrigiert um zum geografischen Norden zu zeigen. Dafür muss auf ihren groben Standort zugegriffen werden.</string>

<string name="haptic_feedback">Haptisches Feedback</string>
<string name="haptic_feedback_summary">Der Kompass vibriert wenn sich die Richtung ändert.</string>

<string name="display">Anzeige</string>
<string name="night_mode">Nachtmodus</string>
<string name="night_mode_follow_system">System</string>
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values-el/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
<!--TODO<string name="true_north">True North</string>-->
<!--TODO<string name="true_north_summary">Correct the magnetic declination and show to true north. Requires access to your coarse location.</string>-->

<!--TODO<string name="haptic_feedback">Haptic feedback</string>-->
<!--TODO<string name="haptic_feedback_summary">The compass vibrates when the direction changes.</string>-->

<!--TODO<string name="display">Display</string>-->
<!--TODO<string name="night_mode">Night mode</string>-->
<!--TODO<string name="night_mode_follow_system">System</string>-->
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values-fi/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
<!--TODO<string name="true_north">True North</string>-->
<!--TODO<string name="true_north_summary">Correct the magnetic declination and show to true north. Requires access to your coarse location.</string>-->

<!--TODO<string name="haptic_feedback">Haptic feedback</string>-->
<!--TODO<string name="haptic_feedback_summary">The compass vibrates when the direction changes.</string>-->

<!--TODO<string name="display">Display</string>-->
<!--TODO<string name="night_mode">Night mode</string>-->
<!--TODO<string name="night_mode_follow_system">System</string>-->
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values-fr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
<!--TODO<string name="true_north">True North</string>-->
<!--TODO<string name="true_north_summary">Correct the magnetic declination and show to true north. Requires access to your coarse location.</string>-->

<!--TODO<string name="haptic_feedback">Haptic feedback</string>-->
<!--TODO<string name="haptic_feedback_summary">The compass vibrates when the direction changes.</string>-->

<!--TODO<string name="display">Display</string>-->
<!--TODO<string name="night_mode">Night mode</string>-->
<!--TODO<string name="night_mode_follow_system">System</string>-->
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values-hr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
<!--TODO<string name="true_north">True North</string>-->
<!--TODO<string name="true_north_summary">Correct the magnetic declination and show to true north. Requires access to your coarse location.</string>-->

<!--TODO<string name="haptic_feedback">Haptic feedback</string>-->
<!--TODO<string name="haptic_feedback_summary">The compass vibrates when the direction changes.</string>-->

<!--TODO<string name="display">Display</string>-->
<!--TODO<string name="night_mode">Night mode</string>-->
<!--TODO<string name="night_mode_follow_system">System</string>-->
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values-mk/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
<!--TODO<string name="true_north">True North</string>-->
<!--TODO<string name="true_north_summary">Correct the magnetic declination and show to true north. Requires access to your coarse location.</string>-->

<!--TODO<string name="haptic_feedback">Haptic feedback</string>-->
<!--TODO<string name="haptic_feedback_summary">The compass vibrates when the direction changes.</string>-->

<!--TODO<string name="display">Display</string>-->
<!--TODO<string name="night_mode">Night mode</string>-->
<!--TODO<string name="night_mode_follow_system">System</string>-->
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values-nl/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
<!--TODO<string name="true_north">True North</string>-->
<!--TODO<string name="true_north_summary">Correct the magnetic declination and show to true north. Requires access to your coarse location.</string>-->

<!--TODO<string name="haptic_feedback">Haptic feedback</string>-->
<!--TODO<string name="haptic_feedback_summary">The compass vibrates when the direction changes.</string>-->

<!--TODO<string name="display">Display</string>-->
<!--TODO<string name="night_mode">Night mode</string>-->
<!--TODO<string name="night_mode_follow_system">System</string>-->
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
<!--TODO<string name="true_north">True North</string>-->
<!--TODO<string name="true_north_summary">Correct the magnetic declination and show to true north. Requires access to your coarse location.</string>-->

<!--TODO<string name="haptic_feedback">Haptic feedback</string>-->
<!--TODO<string name="haptic_feedback_summary">The compass vibrates when the direction changes.</string>-->

<!--TODO<string name="display">Display</string>-->
<!--TODO<string name="night_mode">Night mode</string>-->
<!--TODO<string name="night_mode_follow_system">System</string>-->
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values-sr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
<!--TODO<string name="true_north">True North</string>-->
<!--TODO<string name="true_north_summary">Correct the magnetic declination and show to true north. Requires access to your coarse location.</string>-->

<!--TODO<string name="haptic_feedback">Haptic feedback</string>-->
<!--TODO<string name="haptic_feedback_summary">The compass vibrates when the direction changes.</string>-->

<!--TODO<string name="display">Display</string>-->
<!--TODO<string name="night_mode">Night mode</string>-->
<!--TODO<string name="night_mode_follow_system">System</string>-->
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values-tr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
<!--TODO<string name="true_north">True North</string>-->
<!--TODO<string name="true_north_summary">Correct the magnetic declination and show to true north. Requires access to your coarse location.</string>-->

<!--TODO<string name="haptic_feedback">Haptic feedback</string>-->
<!--TODO<string name="haptic_feedback_summary">The compass vibrates when the direction changes.</string>-->

<!--TODO<string name="display">Display</string>-->
<!--TODO<string name="night_mode">Night mode</string>-->
<!--TODO<string name="night_mode_follow_system">System</string>-->
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
<string name="true_north">True North</string>
<string name="true_north_summary">Correct the magnetic declination and show to true north. Requires access to your coarse location.</string>

<string name="haptic_feedback">Haptic feedback</string>
<string name="haptic_feedback_summary">The compass vibrates when the direction changes.</string>

<string name="display">Display</string>
<string name="night_mode">Night mode</string>
<string name="night_mode_follow_system">System</string>
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/xml/preferences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
app:summary="@string/true_north_summary"
app:defaultValue="false" />

<SwitchPreferenceCompat
app:key="haptic_feedback"
app:title="@string/haptic_feedback"
app:summary="@string/haptic_feedback_summary"
app:defaultValue="true" />

</PreferenceCategory>

<PreferenceCategory
Expand Down
Loading

0 comments on commit 7dfa266

Please sign in to comment.