From 212726d89344f6e621b05e46e7b0f6c7a514cd22 Mon Sep 17 00:00:00 2001 From: Nathan Reline Date: Fri, 24 Apr 2026 16:24:13 -0400 Subject: [PATCH] Add drop-in UI support for Feedback Agent --- examples/src/main/AndroidManifest.xml | 5 + .../navigation/examples/MainActivity.kt | 6 + .../MapboxVoiceFeedbackActivity.kt | 103 ++++++++++ .../layout/layout_activity_voice_feedback.xml | 21 +++ examples/src/main/res/values/strings.xml | 3 + gradle/dependencies.gradle | 1 + gradle/publish.gradle | 1 + libnavigation-android/build.gradle | 1 + .../voicefeedback/FeedbackAgentSession.kt | 7 +- .../audio/microphone/AudioRecordMicrophone.kt | 4 +- libnavui-dropin/build.gradle | 1 + ...iceFeedbackScreenshotComponentInstaller.kt | 31 +++ libnavui-voicefeedback/.gitignore | 2 + libnavui-voicefeedback/build.gradle | 79 ++++++++ libnavui-voicefeedback/gradle.properties | 3 + libnavui-voicefeedback/proguard-rules.pro | 21 +++ .../src/main/AndroidManifest.xml | 3 + .../ui/voicefeedback/ComponentInstaller.kt | 19 ++ .../internal/VoiceFeedbackComponent.kt | 137 ++++++++++++++ .../view/MapboxVoiceFeedbackButton.kt | 82 ++++++++ .../view/MapboxVoiceFeedbackDialog.kt | 176 ++++++++++++++++++ .../view/VoiceFeedbackViewModel.kt | 51 +++++ .../main/res/animator/mapbox_spinner_path.xml | 9 + .../res/animator/mapbox_spinner_rotation.xml | 8 + .../res/animator/pulse_circle_animation.xml | 22 +++ .../mapbox_bg_close_button_circle.xml | 5 + .../mapbox_bg_voice_feedback_dialog.xml | 6 + .../main/res/drawable/mapbox_ic_cancel.xml | 25 +++ .../src/main/res/drawable/mapbox_ic_error.xml | 34 ++++ .../src/main/res/drawable/mapbox_ic_mic.xml | 81 ++++++++ .../res/drawable/mapbox_ic_mic_pulsing.xml | 8 + .../main/res/drawable/mapbox_ic_ok_sign.xml | 5 + .../res/drawable/mapbox_ic_spinner_anim.xml | 11 ++ .../res/drawable/mapbox_ic_spinner_icon.xml | 20 ++ .../res/drawable/mapbox_ic_voice_feedback.xml | 10 + .../mapbox_voice_feedback_bg_button.xml | 10 + .../mapbox_voice_feedback_button_layout.xml | 27 +++ .../mapbox_voice_feedback_dialog_layout.xml | 108 +++++++++++ .../src/main/res/values-ar/strings.xml | 12 ++ .../src/main/res/values-bg/strings.xml | 12 ++ .../src/main/res/values-bs-rBA/strings.xml | 12 ++ .../src/main/res/values-cs/strings.xml | 12 ++ .../src/main/res/values-da/strings.xml | 12 ++ .../src/main/res/values-de/strings.xml | 12 ++ .../src/main/res/values-el/strings.xml | 12 ++ .../src/main/res/values-en-rAU/strings.xml | 12 ++ .../src/main/res/values-en-rGB/strings.xml | 12 ++ .../src/main/res/values-en-rIN/strings.xml | 12 ++ .../src/main/res/values-en-rSG/strings.xml | 12 ++ .../src/main/res/values-en-rUS/strings.xml | 12 ++ .../src/main/res/values-es-rES/strings.xml | 12 ++ .../src/main/res/values-es-rMX/strings.xml | 12 ++ .../src/main/res/values-es/strings.xml | 12 ++ .../src/main/res/values-et/strings.xml | 12 ++ .../src/main/res/values-fi/strings.xml | 12 ++ .../src/main/res/values-fr-rCA/strings.xml | 12 ++ .../src/main/res/values-fr/strings.xml | 12 ++ .../src/main/res/values-hr/strings.xml | 12 ++ .../src/main/res/values-hu/strings.xml | 12 ++ .../src/main/res/values-in/strings.xml | 12 ++ .../src/main/res/values-is/strings.xml | 12 ++ .../src/main/res/values-it/strings.xml | 12 ++ .../src/main/res/values-iw/strings.xml | 12 ++ .../src/main/res/values-ja-rJP/strings.xml | 12 ++ .../src/main/res/values-ja/strings.xml | 12 ++ .../src/main/res/values-ko/strings.xml | 12 ++ .../src/main/res/values-lt/strings.xml | 12 ++ .../src/main/res/values-lv/strings.xml | 12 ++ .../src/main/res/values-ms/strings.xml | 12 ++ .../src/main/res/values-nb/strings.xml | 12 ++ .../src/main/res/values-night/colors.xml | 10 + .../src/main/res/values-nl-rBE/strings.xml | 12 ++ .../src/main/res/values-nl-rNL/strings.xml | 12 ++ .../src/main/res/values-nl/strings.xml | 12 ++ .../src/main/res/values-no-rNO/strings.xml | 12 ++ .../src/main/res/values-pl/strings.xml | 12 ++ .../src/main/res/values-pt-rBR/strings.xml | 12 ++ .../src/main/res/values-pt/strings.xml | 12 ++ .../src/main/res/values-ro/strings.xml | 12 ++ .../src/main/res/values-ru/strings.xml | 12 ++ .../src/main/res/values-sk/strings.xml | 12 ++ .../src/main/res/values-sl/strings.xml | 12 ++ .../src/main/res/values-sq/strings.xml | 12 ++ .../src/main/res/values-sr/strings.xml | 12 ++ .../src/main/res/values-sv/strings.xml | 12 ++ .../main/res/values-sw600dp-land/dimens.xml | 30 +++ .../src/main/res/values-sw600dp/bools.xml | 4 + .../src/main/res/values-th/strings.xml | 12 ++ .../src/main/res/values-tr/strings.xml | 12 ++ .../src/main/res/values-uk/strings.xml | 12 ++ .../src/main/res/values-vi/strings.xml | 12 ++ .../src/main/res/values-zh-rCN/strings.xml | 12 ++ .../src/main/res/values-zh-rHK/strings.xml | 12 ++ .../src/main/res/values-zh-rTW/strings.xml | 12 ++ .../src/main/res/values/attrs.xml | 8 + .../src/main/res/values/bools.xml | 4 + .../src/main/res/values/colors.xml | 11 ++ .../src/main/res/values/dimens.xml | 30 +++ .../src/main/res/values/strings.xml | 12 ++ .../src/main/res/values/styles.xml | 19 ++ .../view/MapboxVoiceFeedbackDialogTest.kt | 86 +++++++++ .../view/VoiceFeedbackViewModelTest.kt | 69 +++++++ .../src/test/resources/robolectric.properties | 1 + settings.gradle | 1 + 104 files changed, 2065 insertions(+), 2 deletions(-) create mode 100644 examples/src/main/java/com/mapbox/navigation/examples/voicefeedback/MapboxVoiceFeedbackActivity.kt create mode 100644 examples/src/main/res/layout/layout_activity_voice_feedback.xml create mode 100644 libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/voicefeedback/VoiceFeedbackScreenshotComponentInstaller.kt create mode 100644 libnavui-voicefeedback/.gitignore create mode 100644 libnavui-voicefeedback/build.gradle create mode 100644 libnavui-voicefeedback/gradle.properties create mode 100644 libnavui-voicefeedback/proguard-rules.pro create mode 100644 libnavui-voicefeedback/src/main/AndroidManifest.xml create mode 100644 libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/ComponentInstaller.kt create mode 100644 libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/internal/VoiceFeedbackComponent.kt create mode 100644 libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/view/MapboxVoiceFeedbackButton.kt create mode 100644 libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/view/MapboxVoiceFeedbackDialog.kt create mode 100644 libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/view/VoiceFeedbackViewModel.kt create mode 100644 libnavui-voicefeedback/src/main/res/animator/mapbox_spinner_path.xml create mode 100644 libnavui-voicefeedback/src/main/res/animator/mapbox_spinner_rotation.xml create mode 100644 libnavui-voicefeedback/src/main/res/animator/pulse_circle_animation.xml create mode 100644 libnavui-voicefeedback/src/main/res/drawable/mapbox_bg_close_button_circle.xml create mode 100644 libnavui-voicefeedback/src/main/res/drawable/mapbox_bg_voice_feedback_dialog.xml create mode 100644 libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_cancel.xml create mode 100644 libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_error.xml create mode 100644 libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_mic.xml create mode 100644 libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_mic_pulsing.xml create mode 100644 libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_ok_sign.xml create mode 100644 libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_spinner_anim.xml create mode 100644 libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_spinner_icon.xml create mode 100644 libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_voice_feedback.xml create mode 100644 libnavui-voicefeedback/src/main/res/drawable/mapbox_voice_feedback_bg_button.xml create mode 100644 libnavui-voicefeedback/src/main/res/layout/mapbox_voice_feedback_button_layout.xml create mode 100644 libnavui-voicefeedback/src/main/res/layout/mapbox_voice_feedback_dialog_layout.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-ar/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-bg/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-bs-rBA/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-cs/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-da/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-de/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-el/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-en-rAU/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-en-rGB/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-en-rIN/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-en-rSG/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-en-rUS/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-es-rES/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-es-rMX/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-es/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-et/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-fi/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-fr-rCA/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-fr/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-hr/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-hu/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-in/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-is/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-it/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-iw/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-ja-rJP/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-ja/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-ko/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-lt/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-lv/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-ms/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-nb/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-night/colors.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-nl-rBE/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-nl-rNL/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-nl/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-no-rNO/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-pl/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-pt-rBR/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-pt/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-ro/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-ru/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-sk/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-sl/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-sq/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-sr/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-sv/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-sw600dp-land/dimens.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-sw600dp/bools.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-th/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-tr/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-uk/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-vi/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-zh-rCN/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-zh-rHK/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values-zh-rTW/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values/attrs.xml create mode 100644 libnavui-voicefeedback/src/main/res/values/bools.xml create mode 100644 libnavui-voicefeedback/src/main/res/values/colors.xml create mode 100644 libnavui-voicefeedback/src/main/res/values/dimens.xml create mode 100644 libnavui-voicefeedback/src/main/res/values/strings.xml create mode 100644 libnavui-voicefeedback/src/main/res/values/styles.xml create mode 100644 libnavui-voicefeedback/src/test/java/com/mapbox/navigation/ui/voicefeedback/view/MapboxVoiceFeedbackDialogTest.kt create mode 100644 libnavui-voicefeedback/src/test/java/com/mapbox/navigation/ui/voicefeedback/view/VoiceFeedbackViewModelTest.kt create mode 100644 libnavui-voicefeedback/src/test/resources/robolectric.properties diff --git a/examples/src/main/AndroidManifest.xml b/examples/src/main/AndroidManifest.xml index 0315b1cb48e..213c4d8bc36 100644 --- a/examples/src/main/AndroidManifest.xml +++ b/examples/src/main/AndroidManifest.xml @@ -101,6 +101,11 @@ android:screenOrientation="portrait"> + + + diff --git a/examples/src/main/java/com/mapbox/navigation/examples/MainActivity.kt b/examples/src/main/java/com/mapbox/navigation/examples/MainActivity.kt index dcb54683038..c0132bb7ec3 100644 --- a/examples/src/main/java/com/mapbox/navigation/examples/MainActivity.kt +++ b/examples/src/main/java/com/mapbox/navigation/examples/MainActivity.kt @@ -33,6 +33,7 @@ import com.mapbox.navigation.examples.core.databinding.LayoutActivityMainBinding import com.mapbox.navigation.examples.util.LocationPermissionsHelper import com.mapbox.navigation.examples.util.LocationPermissionsHelper.Companion.areLocationPermissionsGranted import com.mapbox.navigation.examples.util.RouteDrawingActivity +import com.mapbox.navigation.examples.voicefeedback.MapboxVoiceFeedbackActivity class MainActivity : AppCompatActivity(), PermissionsListener { @@ -148,6 +149,11 @@ class MainActivity : AppCompatActivity(), PermissionsListener { getString(R.string.title_adasis), getString(R.string.description_adasis), AdasisActivity::class.java + ), + SampleItem( + getString(R.string.title_voice_feedback), + getString(R.string.description_voice_feedback), + MapboxVoiceFeedbackActivity::class.java ) ) } diff --git a/examples/src/main/java/com/mapbox/navigation/examples/voicefeedback/MapboxVoiceFeedbackActivity.kt b/examples/src/main/java/com/mapbox/navigation/examples/voicefeedback/MapboxVoiceFeedbackActivity.kt new file mode 100644 index 00000000000..ee500f7913d --- /dev/null +++ b/examples/src/main/java/com/mapbox/navigation/examples/voicefeedback/MapboxVoiceFeedbackActivity.kt @@ -0,0 +1,103 @@ +package com.mapbox.navigation.examples.voicefeedback + +import android.Manifest +import android.os.Bundle +import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AppCompatActivity +import com.mapbox.maps.MapboxMap +import com.mapbox.maps.plugin.locationcomponent.location +import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI +import com.mapbox.navigation.base.options.NavigationOptions +import com.mapbox.navigation.core.MapboxNavigation +import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp +import com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver +import com.mapbox.navigation.core.lifecycle.requireMapboxNavigation +import com.mapbox.navigation.examples.core.databinding.LayoutActivityVoiceFeedbackBinding +import com.mapbox.navigation.examples.util.Utils +import com.mapbox.navigation.ui.base.installer.installComponents +import com.mapbox.navigation.ui.maps.location.NavigationLocationProvider +import com.mapbox.navigation.ui.voicefeedback.voiceFeedbackButton + +/** + * Example activity demonstrating the [libnavui-voicefeedback](https://docs.mapbox.com/android/navigation/ui/latest/libnavui-voicefeedback/overview/) + * SDK. This SDK provides voice feedback capabilities, allowing users to report issues, + * suggest improvements, or give feedback directly through voice while navigating. + * + * It utilizes [MapboxVoiceFeedbackButton] and [FeedbackAgentSession] (via the ComponentInstaller) + * to manage the lifecycle and UI states of the voice interaction flow. + */ +@OptIn(ExperimentalPreviewMapboxNavigationAPI::class) +class MapboxVoiceFeedbackActivity : AppCompatActivity() { + + private val navigationLocationProvider = NavigationLocationProvider() + private lateinit var binding: LayoutActivityVoiceFeedbackBinding + private lateinit var mapboxMap: MapboxMap + private val mapboxNavigation: MapboxNavigation by requireMapboxNavigation( + onResumedObserver = object : MapboxNavigationObserver { + override fun onAttached(mapboxNavigation: MapboxNavigation) { + } + + override fun onDetached(mapboxNavigation: MapboxNavigation) { + } + }, + onInitialize = this::initNavigation + ) + + private val requestPermissionLauncher = registerForActivityResult( + ActivityResultContracts.RequestMultiplePermissions() + ) { permissions -> + val areGranted = permissions.values.all { it } + if (areGranted) { + mapboxNavigation.startTripSession() + } else { + Toast.makeText( + this, + "Location and Microphone permissions are required", + Toast.LENGTH_LONG + ).show() + finish() + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = LayoutActivityVoiceFeedbackBinding.inflate(layoutInflater) + setContentView(binding.root) + + mapboxMap = binding.mapView.getMapboxMap() + + requestPermissionLauncher.launch( + arrayOf( + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.RECORD_AUDIO + ) + ) + } + + private fun initNavigation() { + if (!MapboxNavigationApp.isSetup()) { + MapboxNavigationApp.setup( + NavigationOptions.Builder(this) + .accessToken(Utils.getMapboxAccessToken(this)) + .build() + ) + } + + MapboxNavigationApp.installComponents(this) { + voiceFeedbackButton(binding.voiceFeedbackButton) + } + + binding.mapView.location.apply { + enabled = true + setLocationProvider(navigationLocationProvider) + } + + mapboxMap.setCamera( + com.mapbox.maps.CameraOptions.Builder() + .center(com.mapbox.geojson.Point.fromLngLat(-73.98513, 40.748817)) // New York City + .zoom(13.0) + .build() + ) + } +} diff --git a/examples/src/main/res/layout/layout_activity_voice_feedback.xml b/examples/src/main/res/layout/layout_activity_voice_feedback.xml new file mode 100644 index 00000000000..dbacd1fc037 --- /dev/null +++ b/examples/src/main/res/layout/layout_activity_voice_feedback.xml @@ -0,0 +1,21 @@ + + + + + + + + diff --git a/examples/src/main/res/values/strings.xml b/examples/src/main/res/values/strings.xml index 79afad8bcd0..ca1df0476f2 100644 --- a/examples/src/main/res/values/strings.xml +++ b/examples/src/main/res/values/strings.xml @@ -39,6 +39,9 @@ Adasis Example Demonstrates to to access Adasis functionality. + Voice Feedback Example + Demonstrates the use of voice feedback API. + Start Navigation Play history Select history diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 18d8995bd9f..fae0a6494a0 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -141,6 +141,7 @@ ext { androidStartup : "androidx.startup:startup-runtime:${version.androidStartup}", androidXFragment : "androidx.fragment:fragment-ktx:${version.androidXFragmentVersion}", androidXArchCoreTesting : "androidx.arch.core:core-testing:${version.androidXArchCoreVersion}", + androidXFragmentTesting : "androidx.fragment:fragment-testing:${version.androidXFragmentVersion}", androidXDataStore : "androidx.datastore:datastore-preferences:${version.androidXDataStore}", androidXWorkManager : "androidx.work:work-runtime-ktx:${version.androidXWorkManager}", diff --git a/gradle/publish.gradle b/gradle/publish.gradle index 88366d61fe6..9e30f859f49 100644 --- a/gradle/publish.gradle +++ b/gradle/publish.gradle @@ -74,6 +74,7 @@ sdkNameMap["libnavui-tripprogress"] = "mobile-navigation-ui-tripprogress" sdkNameMap["libnavui-maneuver"] = "mobile-navigation-ui-maneuver" sdkNameMap["libnavui-resources"] = "mobile-navigation-ui-resources" sdkNameMap["libnavui-voice"] = "mobile-navigation-ui-voice" +sdkNameMap["libnavui-voicefeedback"] = "mobile-navigation-ui-voicefeedback" sdkNameMap["libnavui-speedlimit"] = "mobile-navigation-ui-speedlimit" sdkNameMap["libnavui-shield"] = "mobile-navigation-ui-shield" sdkNameMap["libnavui-status"] = "mobile-navigation-ui-status" diff --git a/libnavigation-android/build.gradle b/libnavigation-android/build.gradle index 22795f76ce2..e17831df33a 100644 --- a/libnavigation-android/build.gradle +++ b/libnavigation-android/build.gradle @@ -34,6 +34,7 @@ dependencies { api project(":libnavui-speedlimit") api project(":libnavui-tripprogress") api project(":libnavui-voice") + api project(":libnavui-voicefeedback") api project(":libnavui-status") } diff --git a/libnavigation-voicefeedback/src/main/java/com/mapbox/navigation/voicefeedback/FeedbackAgentSession.kt b/libnavigation-voicefeedback/src/main/java/com/mapbox/navigation/voicefeedback/FeedbackAgentSession.kt index ed67e1c18ef..e006f11ec98 100644 --- a/libnavigation-voicefeedback/src/main/java/com/mapbox/navigation/voicefeedback/FeedbackAgentSession.kt +++ b/libnavigation-voicefeedback/src/main/java/com/mapbox/navigation/voicefeedback/FeedbackAgentSession.kt @@ -197,7 +197,12 @@ class FeedbackAgentSession private constructor( engine.disconnect() } - private companion object { + companion object { private const val TAG = "FeedbackAgentSession" + + @JvmStatic + fun getRegisteredInstance(): FeedbackAgentSession = MapboxNavigationApp + .getObservers(FeedbackAgentSession::class) + .firstOrNull() ?: Builder().build().also { MapboxNavigationApp.registerObserver(it) } } } diff --git a/libnavigation-voicefeedback/src/main/java/com/mapbox/navigation/voicefeedback/internal/audio/microphone/AudioRecordMicrophone.kt b/libnavigation-voicefeedback/src/main/java/com/mapbox/navigation/voicefeedback/internal/audio/microphone/AudioRecordMicrophone.kt index 8855eb6f004..fd5ef4c5fed 100644 --- a/libnavigation-voicefeedback/src/main/java/com/mapbox/navigation/voicefeedback/internal/audio/microphone/AudioRecordMicrophone.kt +++ b/libnavigation-voicefeedback/src/main/java/com/mapbox/navigation/voicefeedback/internal/audio/microphone/AudioRecordMicrophone.kt @@ -185,7 +185,9 @@ internal class AudioRecordMicrophone : Microphone { logD(TAG) { "After startRecording: ${AudioInfoRetriever.stateString(audioRecord)}" } cont.invokeOnCancellation { logD(TAG) { "stream cancelled, calling audioRecord.stop()" } - audioRecord.stop() + if (audioRecord.recordingState == AudioRecord.RECORDSTATE_RECORDING) { + audioRecord.stop() + } } while ( cont.isActive && diff --git a/libnavui-dropin/build.gradle b/libnavui-dropin/build.gradle index 93bc336a334..fd85ee31756 100644 --- a/libnavui-dropin/build.gradle +++ b/libnavui-dropin/build.gradle @@ -48,6 +48,7 @@ dependencies { api project(":libnavui-speedlimit") api project(":libnavui-tripprogress") api project(":libnavui-voice") + api project(":libnavui-voicefeedback") implementation project(":libnavui-app") api dependenciesList.mapboxSdkServices diff --git a/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/voicefeedback/VoiceFeedbackScreenshotComponentInstaller.kt b/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/voicefeedback/VoiceFeedbackScreenshotComponentInstaller.kt new file mode 100644 index 00000000000..c873e26c2e3 --- /dev/null +++ b/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/voicefeedback/VoiceFeedbackScreenshotComponentInstaller.kt @@ -0,0 +1,31 @@ +package com.mapbox.navigation.dropin.voicefeedback + +import com.mapbox.maps.MapView +import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI +import com.mapbox.navigation.ui.base.installer.ComponentInstaller +import com.mapbox.navigation.ui.base.installer.Installation +import com.mapbox.navigation.ui.maps.util.ViewUtils.capture +import com.mapbox.navigation.ui.voicefeedback.internal.ScreenshotCapturer +import com.mapbox.navigation.ui.voicefeedback.internal.VoiceFeedbackComponent +import com.mapbox.navigation.ui.voicefeedback.view.MapboxVoiceFeedbackButton + +/** + * Installs the voice feedback button component into the current Mapbox Navigation flow. + * + * @param mapView The [MapView] that will be used to capture screenshots during feedback. Leave null + * if you don't want to capture screenshots. + * @param button The visual representation of the voice feedback button. + * @return An [Installation] handle that can be used to remove the component. + */ +@ExperimentalPreviewMapboxNavigationAPI +fun ComponentInstaller.voiceFeedbackButton( + mapView: MapView? = null, + button: MapboxVoiceFeedbackButton, +): Installation { + val screenshotCapturer = mapView?.let { + ScreenshotCapturer { callback -> + it.capture { screenshot -> callback(screenshot) } + } + } + return component(VoiceFeedbackComponent(button, screenshotCapturer)) +} diff --git a/libnavui-voicefeedback/.gitignore b/libnavui-voicefeedback/.gitignore new file mode 100644 index 00000000000..c2a44471591 --- /dev/null +++ b/libnavui-voicefeedback/.gitignore @@ -0,0 +1,2 @@ +/build +src/main/assets/sdk_versions/* \ No newline at end of file diff --git a/libnavui-voicefeedback/build.gradle b/libnavui-voicefeedback/build.gradle new file mode 100644 index 00000000000..904b9f2fbe9 --- /dev/null +++ b/libnavui-voicefeedback/build.gradle @@ -0,0 +1,79 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' +apply plugin: 'kotlin-parcelize' +apply plugin: 'org.jetbrains.dokka' +apply plugin: 'com.jaredsburrows.license' +apply plugin: 'com.mapbox.android.sdk.versions' +apply from: "../gradle/ktlint.gradle" +apply from: file("../gradle/artifact-settings.gradle") +apply from: "../gradle/kdoc-settings.gradle" + +version = project.ext.versionName +group = project.ext.mapboxArtifactGroupId + +android { + compileSdkVersion androidVersions.compileSdkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + defaultConfig { + minSdkVersion androidVersions.minSdkVersion + targetSdkVersion androidVersions.targetSdkVersion + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles 'proguard-rules.pro', "../proguard/proguard-project.pro" + } + + testOptions { + unitTests.returnDefaultValues = true + unitTests.includeAndroidResources = true + } + + buildFeatures { + viewBinding true + } +} + +dependencies { + api project(":libnavigation-voicefeedback") + api project(":libnavui-base") + implementation project(":libnavui-resources") + + api dependenciesList.mapboxSdkServices + + implementation dependenciesList.kotlinStdLib + + implementation dependenciesList.coroutinesAndroid + + // androidX + implementation dependenciesList.androidXConstraintLayout + implementation dependenciesList.androidXAppCompat + implementation dependenciesList.androidXCoreKtx + implementation dependenciesList.androidXLifecycleViewmodel + + apply from: "../gradle/unit-testing-dependencies.gradle" + testImplementation(project(':libtesting-utils')) + testImplementation project(':libtesting-navigation-util') + testImplementation dependenciesList.androidXFragmentTesting +} + +dokkaHtmlPartial { + outputDirectory.set(kdocPath) + moduleName.set("UI Feedback Agent") + dokkaSourceSets { + configureEach { + reportUndocumented.set(true) + perPackageOption { + matchingRegex.set("com.mapbox.navigation.ui.voicefeedback.internal.*") + suppress.set(true) + } + } + } +} + +apply from: "../gradle/track-public-apis.gradle" +apply from: "../gradle/jacoco.gradle" +apply from: "../gradle/publish.gradle" diff --git a/libnavui-voicefeedback/gradle.properties b/libnavui-voicefeedback/gradle.properties new file mode 100644 index 00000000000..01017c63583 --- /dev/null +++ b/libnavui-voicefeedback/gradle.properties @@ -0,0 +1,3 @@ +POM_ARTIFACT_ID=ui-voicefeedback +POM_ARTIFACT_TITLE=Mapbox Navigation Feedback Agent +POM_DESCRIPTION=Artifact that provides ability to collect feedback using voice \ No newline at end of file diff --git a/libnavui-voicefeedback/proguard-rules.pro b/libnavui-voicefeedback/proguard-rules.pro new file mode 100644 index 00000000000..481bb434814 --- /dev/null +++ b/libnavui-voicefeedback/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/libnavui-voicefeedback/src/main/AndroidManifest.xml b/libnavui-voicefeedback/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..3dbf7681d34 --- /dev/null +++ b/libnavui-voicefeedback/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/ComponentInstaller.kt b/libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/ComponentInstaller.kt new file mode 100644 index 00000000000..0edf6826dac --- /dev/null +++ b/libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/ComponentInstaller.kt @@ -0,0 +1,19 @@ +package com.mapbox.navigation.ui.voicefeedback + +import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI +import com.mapbox.navigation.ui.base.installer.ComponentInstaller +import com.mapbox.navigation.ui.base.installer.Installation +import com.mapbox.navigation.ui.voicefeedback.internal.VoiceFeedbackComponent +import com.mapbox.navigation.ui.voicefeedback.view.MapboxVoiceFeedbackButton + +/** + * Installs the voice feedback button component into the current Mapbox Navigation flow. + * + * @param button The visual representation of the voice feedback button. + * @return An [Installation] handle that can be used to remove the component. + */ +@ExperimentalPreviewMapboxNavigationAPI +fun ComponentInstaller.voiceFeedbackButton(button: MapboxVoiceFeedbackButton): Installation { + return component(VoiceFeedbackComponent(button)) +} + diff --git a/libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/internal/VoiceFeedbackComponent.kt b/libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/internal/VoiceFeedbackComponent.kt new file mode 100644 index 00000000000..ec83af692e6 --- /dev/null +++ b/libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/internal/VoiceFeedbackComponent.kt @@ -0,0 +1,137 @@ +package com.mapbox.navigation.ui.voicefeedback.internal + +import android.content.Context +import android.content.ContextWrapper +import android.graphics.Bitmap +import androidx.fragment.app.FragmentActivity +import androidx.fragment.app.FragmentManager +import androidx.lifecycle.ViewModelProvider +import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI +import com.mapbox.navigation.core.MapboxNavigation +import com.mapbox.navigation.core.internal.telemetry.UserFeedbackCallback +import com.mapbox.navigation.core.telemetry.events.FeedbackHelper +import com.mapbox.navigation.ui.base.lifecycle.UIComponent +import com.mapbox.navigation.ui.voicefeedback.view.MapboxVoiceFeedbackButton +import com.mapbox.navigation.ui.voicefeedback.view.MapboxVoiceFeedbackDialog +import com.mapbox.navigation.ui.voicefeedback.view.VoiceFeedbackViewModel +import com.mapbox.navigation.utils.internal.logE +import com.mapbox.navigation.voicefeedback.ASRState +import com.mapbox.navigation.voicefeedback.postVoiceFeedback +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlin.coroutines.resume + +/** + * Interface for capturing map screenshots to be included with feedback. + */ +@ExperimentalPreviewMapboxNavigationAPI +fun interface ScreenshotCapturer { + /** + * @param callback Callback to be invoked with the captured screenshot as a [Bitmap]. + */ + fun capture(callback: (Bitmap) -> Unit) +} + +/** + * UI component that orchestrates the voice feedback flow: button interaction, + * [VoiceFeedbackViewModel] lifecycle, ASR dialog, screenshot capture, and feedback posting. + * + * @param button the voice feedback button view that triggers the flow + * @param screenshotCapturer optional screenshot capturer that can be used to capture screenshots + * before posting feedback. + */ +@ExperimentalPreviewMapboxNavigationAPI +class VoiceFeedbackComponent( + private val button: MapboxVoiceFeedbackButton, + private val screenshotCapturer: ScreenshotCapturer? = null, +) : UIComponent() { + + private var mapboxNavigation: MapboxNavigation? = null + private var viewModel: VoiceFeedbackViewModel? = null + + override fun onAttached(mapboxNavigation: MapboxNavigation) { + super.onAttached(mapboxNavigation) + this.mapboxNavigation = mapboxNavigation + + val activity = button.context.findFragmentActivity() ?: run { + logE(TAG) { "Cannot attach: host Activity is not a FragmentActivity" } + return + } + val viewModel = ViewModelProvider(activity)[VoiceFeedbackViewModel::class.java] + this.viewModel = viewModel + + coroutineScope.launch { + viewModel.state.collect { state -> + if (state is ASRState.Result) { + postFeedback(state) + } + } + } + + button.setOnClickListener { + showDialog() + viewModel.onVoiceFeedbackButtonClicked() + } + } + + private fun showDialog() { + val fragmentManager = + button.context.findFragmentManager() ?: run { + logE(TAG) { "Cannot update dialog: host Activity is not a FragmentActivity" } + return + } + + MapboxVoiceFeedbackDialog().show(fragmentManager, MapboxVoiceFeedbackDialog.TAG) + } + + override fun onDetached(mapboxNavigation: MapboxNavigation) { + button.setOnClickListener(null) + this.viewModel = null + this.mapboxNavigation = null + super.onDetached(mapboxNavigation) + } + + private suspend fun captureScreenshot(): Bitmap? = suspendCancellableCoroutine { cont -> + if (screenshotCapturer != null) { + screenshotCapturer.capture { + if (cont.isActive) cont.resume(it) + } + } else { + cont.resume(null) + } + } + + private suspend fun postFeedback(result: ASRState.Result) { + val nav = mapboxNavigation ?: return + val screenshot = captureScreenshot()?.let { + FeedbackHelper.encodeScreenshot(it) + } ?: "" + nav.postVoiceFeedback( + feedbackSubType = result.feedbackType, + description = result.text, + screenshot = screenshot, + userFeedbackCallback = UserFeedbackCallback {/*no-op*/}, + ) + } + + private companion object { + private const val TAG = "VoiceFeedbackComponent" + } +} + +private fun Context.findFragmentManager(): FragmentManager? { + var ctx = this + while (true) { + if (ctx is FragmentActivity) return ctx.supportFragmentManager + if (ctx is ContextWrapper) ctx = ctx.baseContext else return null + } +} + +private fun Context.findFragmentActivity(): FragmentActivity? { + var ctx = this + while (true) { + if (ctx is FragmentActivity) return ctx + if (ctx is ContextWrapper) ctx = ctx.baseContext else return null + } +} diff --git a/libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/view/MapboxVoiceFeedbackButton.kt b/libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/view/MapboxVoiceFeedbackButton.kt new file mode 100644 index 00000000000..746dd134755 --- /dev/null +++ b/libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/view/MapboxVoiceFeedbackButton.kt @@ -0,0 +1,82 @@ +package com.mapbox.navigation.ui.voicefeedback.view + +import android.content.Context +import android.content.res.TypedArray +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.FrameLayout +import android.widget.ImageView +import androidx.annotation.StyleRes +import androidx.annotation.UiThread +import androidx.core.content.ContextCompat +import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI +import com.mapbox.navigation.ui.voicefeedback.R +import com.mapbox.navigation.ui.voicefeedback.databinding.MapboxVoiceFeedbackButtonLayoutBinding + +@ExperimentalPreviewMapboxNavigationAPI +@UiThread +class MapboxVoiceFeedbackButton : FrameLayout { + private val binding = + MapboxVoiceFeedbackButtonLayoutBinding.inflate(LayoutInflater.from(context), this) + + val iconImage: ImageView = binding.iconImage + + constructor(context: Context) : this(context, null) + + constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : + this(context, attrs, defStyleAttr, R.style.MapboxStyleVoiceFeedbackButton) + + constructor( + context: Context, + attrs: AttributeSet?, + defStyleAttr: Int, + defStyleRes: Int, + ) : super(context, attrs, defStyleAttr, defStyleRes) { + context.theme + .obtainStyledAttributes( + attrs, + R.styleable.MapboxVoiceFeedbackButton, + defStyleAttr, + defStyleRes, + ).apply { + try { + applyAttributes(this) + } finally { + recycle() + } + } + } + + fun updateStyle( + @StyleRes style: Int, + ) { + context.obtainStyledAttributes(style, R.styleable.MapboxVoiceFeedbackButton).apply { + try { + applyAttributes(this) + } finally { + recycle() + } + } + } + + private fun applyAttributes(typedArray: TypedArray) { + typedArray + .getResourceId( + R.styleable.MapboxVoiceFeedbackButton_voiceFeedbackButtonIcon, + R.drawable.mapbox_ic_voice_feedback, + ).also { + iconImage.setImageResource(it) + } + typedArray + .getColorStateList( + R.styleable.MapboxVoiceFeedbackButton_voiceFeedbackButtonIconTint, + )?.also { + iconImage.imageTintList = it + } + background = + typedArray.getDrawable(R.styleable.MapboxVoiceFeedbackButton_voiceFeedbackButtonBackground) + ?: ContextCompat.getDrawable(context, R.drawable.mapbox_voice_feedback_bg_button) + } +} diff --git a/libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/view/MapboxVoiceFeedbackDialog.kt b/libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/view/MapboxVoiceFeedbackDialog.kt new file mode 100644 index 00000000000..bbe5b8e233c --- /dev/null +++ b/libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/view/MapboxVoiceFeedbackDialog.kt @@ -0,0 +1,176 @@ +package com.mapbox.navigation.ui.voicefeedback.view + +import android.app.Dialog +import android.content.DialogInterface +import android.content.res.Configuration +import android.content.res.Resources +import android.graphics.Color +import android.graphics.drawable.AnimatedVectorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND +import android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL +import androidx.core.view.isVisible +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI +import com.mapbox.navigation.ui.voicefeedback.R +import com.mapbox.navigation.ui.voicefeedback.databinding.MapboxVoiceFeedbackDialogLayoutBinding +import com.mapbox.navigation.voicefeedback.ASRState +import kotlinx.coroutines.launch +import androidx.core.graphics.drawable.toDrawable +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.collectLatest + +@ExperimentalPreviewMapboxNavigationAPI +class MapboxVoiceFeedbackDialog : DialogFragment() { + + private lateinit var binding: MapboxVoiceFeedbackDialogLayoutBinding + private lateinit var viewModel: VoiceFeedbackViewModel + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return Dialog(requireContext(), theme) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + return MapboxVoiceFeedbackDialogLayoutBinding.inflate(inflater, container, false) + .also { binding = it } + .root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + viewModel = ViewModelProvider(requireActivity())[VoiceFeedbackViewModel::class.java] + + dialog?.window?.apply { + val width = if (resources.isTablet() || resources.configuration.isLandscape()) { + ViewGroup.LayoutParams.WRAP_CONTENT + } else { + ViewGroup.LayoutParams.MATCH_PARENT + } + setLayout(width, ViewGroup.LayoutParams.WRAP_CONTENT) + setBackgroundDrawable(Color.TRANSPARENT.toDrawable()) + setGravity(Gravity.BOTTOM) + setFlags(FLAG_NOT_TOUCH_MODAL, FLAG_NOT_TOUCH_MODAL) + clearFlags(FLAG_DIM_BEHIND) + } + + binding.closeButton.setOnClickListener { + dismissAllowingStateLoss() + viewModel.onCloseDialogButtonClicked() + } + + viewLifecycleOwner.lifecycleScope.launch { + launch { + viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.CREATED) { + viewModel.state.collectLatest { state -> renderState(state) } + } + } + } + + viewModel.onDialogVisible() + } + + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + viewModel.onDialogDismissed() + } + + private suspend fun renderState(state: ASRState?) { + when (state) { + ASRState.Idle, null -> showContentBlock( + icon = R.drawable.mapbox_ic_spinner_anim, + header = R.string.mapbox_voice_feedback__share_your_feedback, + description = R.string.mapbox_voice_feedback__connecting, + ) + is ASRState.Listening -> showContentBlock( + icon = R.drawable.mapbox_ic_mic_pulsing, + header = R.string.mapbox_voice_feedback__share_your_feedback, + description = R.string.mapbox_voice_feedback__listening, + ) + is ASRState.SpeechFinishedWaitingForResult -> showContentBlock( + icon = R.drawable.mapbox_ic_spinner_anim, + header = R.string.mapbox_voice_feedback__share_your_feedback, + description = R.string.mapbox_voice_feedback__processing, + ) + + is ASRState.Error, + is ASRState.Interrupted, + is ASRState.InterruptedByTimeout -> { + showInfoBlock( + icon = R.drawable.mapbox_ic_error, + header = R.string.mapbox_voice_feedback__error_title, + description = R.string.mapbox_voice_feedback__error_description, + ) + dismissWithDelay() + } + is ASRState.NoResult -> { + showInfoBlock( + icon = R.drawable.mapbox_ic_error, + header = R.string.mapbox_voice_feedback__speech_not_recognized_title, + description = R.string.mapbox_voice_feedback__error_description, + ) + dismissWithDelay() + } + is ASRState.Result -> { + showInfoBlock( + icon = R.drawable.mapbox_ic_ok_sign, + header = R.string.mapbox_voice_feedback__success_title, + description = R.string.mapbox_voice_feedback__success_description, + ) + dismissWithDelay() + } + } + } + + private fun showContentBlock( + icon: Int, + header: Int, + description: Int, + ) = with(binding) { + binding.contentBlock.isVisible = true + binding.infoBlock.isVisible = false + contentIconImage.setImageResource(icon) + (contentIconImage.drawable as? AnimatedVectorDrawable)?.start() + contentHeader.setText(header) + contentDescription.setText(description) + } + + private fun showInfoBlock( + icon: Int, + header: Int, + description: Int, + ) = with(binding) { + binding.contentBlock.isVisible = false + binding.infoBlock.isVisible = true + infoIcon.setImageResource(icon) + infoHeader.setText(header) + infoDescription.setText(description) + } + + private suspend fun dismissWithDelay(delay: Long = AUTO_DISMISS_DELAY_MS) { + delay(delay) + dismissAllowingStateLoss() + } + + companion object Companion { + internal const val TAG = "VoiceFeedbackDialog" + private const val AUTO_DISMISS_DELAY_MS = 3_000L + } +} + +private fun Resources.isTablet(): Boolean = getBoolean(R.bool.is_tablet) + +private fun Configuration.isLandscape(): Boolean = orientation == + Configuration.ORIENTATION_LANDSCAPE diff --git a/libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/view/VoiceFeedbackViewModel.kt b/libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/view/VoiceFeedbackViewModel.kt new file mode 100644 index 00000000000..becad0ccb10 --- /dev/null +++ b/libnavui-voicefeedback/src/main/java/com/mapbox/navigation/ui/voicefeedback/view/VoiceFeedbackViewModel.kt @@ -0,0 +1,51 @@ +package com.mapbox.navigation.ui.voicefeedback.view + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI +import com.mapbox.navigation.voicefeedback.ASRState +import com.mapbox.navigation.voicefeedback.FeedbackAgentSession +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.launch + +@ExperimentalPreviewMapboxNavigationAPI +internal class VoiceFeedbackViewModel( + private val session: FeedbackAgentSession = FeedbackAgentSession.getRegisteredInstance(), +) : ViewModel() { + + val state: StateFlow get() = session.asrState + + private val isDialogVisible = MutableStateFlow(false) + + init { + session.connect() + } + + fun onVoiceFeedbackButtonClicked() { + viewModelScope.launch { + // wait until session is idle and dialog is visible before starting microphone + combine(session.asrState, isDialogVisible) { state, isDialogVisible -> + state to isDialogVisible + }.firstOrNull { (state, isDialogVisible) -> + state != null && isDialogVisible + } + + session.startListening() + } + } + + fun onCloseDialogButtonClicked() { + session.interruptListening() + } + + fun onDialogVisible() { + isDialogVisible.value = true + } + + fun onDialogDismissed() { + isDialogVisible.value = false + } +} diff --git a/libnavui-voicefeedback/src/main/res/animator/mapbox_spinner_path.xml b/libnavui-voicefeedback/src/main/res/animator/mapbox_spinner_path.xml new file mode 100644 index 00000000000..46793bc8295 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/animator/mapbox_spinner_path.xml @@ -0,0 +1,9 @@ + diff --git a/libnavui-voicefeedback/src/main/res/animator/mapbox_spinner_rotation.xml b/libnavui-voicefeedback/src/main/res/animator/mapbox_spinner_rotation.xml new file mode 100644 index 00000000000..5e5fcf25b5f --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/animator/mapbox_spinner_rotation.xml @@ -0,0 +1,8 @@ + diff --git a/libnavui-voicefeedback/src/main/res/animator/pulse_circle_animation.xml b/libnavui-voicefeedback/src/main/res/animator/pulse_circle_animation.xml new file mode 100644 index 00000000000..17153abe45b --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/animator/pulse_circle_animation.xml @@ -0,0 +1,22 @@ + + + + + + diff --git a/libnavui-voicefeedback/src/main/res/drawable/mapbox_bg_close_button_circle.xml b/libnavui-voicefeedback/src/main/res/drawable/mapbox_bg_close_button_circle.xml new file mode 100644 index 00000000000..abbf895e00e --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/drawable/mapbox_bg_close_button_circle.xml @@ -0,0 +1,5 @@ + + + + diff --git a/libnavui-voicefeedback/src/main/res/drawable/mapbox_bg_voice_feedback_dialog.xml b/libnavui-voicefeedback/src/main/res/drawable/mapbox_bg_voice_feedback_dialog.xml new file mode 100644 index 00000000000..a704200683f --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/drawable/mapbox_bg_voice_feedback_dialog.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_cancel.xml b/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_cancel.xml new file mode 100644 index 00000000000..f3a448e1d21 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_cancel.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_error.xml b/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_error.xml new file mode 100644 index 00000000000..6798e390bd5 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_error.xml @@ -0,0 +1,34 @@ + + + + \ No newline at end of file diff --git a/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_mic.xml b/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_mic.xml new file mode 100644 index 00000000000..30f98466170 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_mic.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + diff --git a/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_mic_pulsing.xml b/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_mic_pulsing.xml new file mode 100644 index 00000000000..0f0d9339995 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_mic_pulsing.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_ok_sign.xml b/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_ok_sign.xml new file mode 100644 index 00000000000..1fcce4dbaf7 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_ok_sign.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_spinner_anim.xml b/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_spinner_anim.xml new file mode 100644 index 00000000000..e0f25668516 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_spinner_anim.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_spinner_icon.xml b/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_spinner_icon.xml new file mode 100644 index 00000000000..c0bb62f07f1 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_spinner_icon.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_voice_feedback.xml b/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_voice_feedback.xml new file mode 100644 index 00000000000..add00b49cb2 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/drawable/mapbox_ic_voice_feedback.xml @@ -0,0 +1,10 @@ + + + diff --git a/libnavui-voicefeedback/src/main/res/drawable/mapbox_voice_feedback_bg_button.xml b/libnavui-voicefeedback/src/main/res/drawable/mapbox_voice_feedback_bg_button.xml new file mode 100644 index 00000000000..c90e76ee24d --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/drawable/mapbox_voice_feedback_bg_button.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/libnavui-voicefeedback/src/main/res/layout/mapbox_voice_feedback_button_layout.xml b/libnavui-voicefeedback/src/main/res/layout/mapbox_voice_feedback_button_layout.xml new file mode 100644 index 00000000000..3914f6b9f1a --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/layout/mapbox_voice_feedback_button_layout.xml @@ -0,0 +1,27 @@ + + + + + + + + + + diff --git a/libnavui-voicefeedback/src/main/res/layout/mapbox_voice_feedback_dialog_layout.xml b/libnavui-voicefeedback/src/main/res/layout/mapbox_voice_feedback_dialog_layout.xml new file mode 100644 index 00000000000..fabda323f6b --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/layout/mapbox_voice_feedback_dialog_layout.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/libnavui-voicefeedback/src/main/res/values-ar/strings.xml b/libnavui-voicefeedback/src/main/res/values-ar/strings.xml new file mode 100644 index 00000000000..b1524b41dda --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-ar/strings.xml @@ -0,0 +1,12 @@ + + + شاركنا ملاحظاتك + جارٍ الاستماع... + جارٍ المعالجة… + شكرًا لمشاركتك + ملاحظاتك تساعدنا على التحسن + عذرًا! حدث خطأ ما + يرجى المحاولة مرة أخرى + عذرًا! لم أسمع ذلك جيدًا + لا يوجد اتصال + diff --git a/libnavui-voicefeedback/src/main/res/values-bg/strings.xml b/libnavui-voicefeedback/src/main/res/values-bg/strings.xml new file mode 100644 index 00000000000..830b5bb4878 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-bg/strings.xml @@ -0,0 +1,12 @@ + + + Споделете вашето мнение + Слушане... + Обработва се… + Благодаря, че сподели + Вашата обратна връзка ни помага да се подобряваме + Опа! Нещо се обърка + Моля, опитайте отново + Опа! Не разбрах това + Няма връзка + diff --git a/libnavui-voicefeedback/src/main/res/values-bs-rBA/strings.xml b/libnavui-voicefeedback/src/main/res/values-bs-rBA/strings.xml new file mode 100644 index 00000000000..ac9d373f2e4 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-bs-rBA/strings.xml @@ -0,0 +1,12 @@ + + + Podijelite svoje mišljenje + Slušanje… + Obrada… + Hvala što ste podijelili + Vaše povratne informacije nam pomažu da se poboljšamo + Ups! Nešto je pošlo po zlu + Pokušajte ponovo + Ups! Nisam to uhvatio/uhvatila + Nema veze + diff --git a/libnavui-voicefeedback/src/main/res/values-cs/strings.xml b/libnavui-voicefeedback/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000000..104d8832625 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-cs/strings.xml @@ -0,0 +1,12 @@ + + + Sdílejte svou zpětnou vazbu + Naslouchám… + Zpracovává se… + Děkuji za sdílení + Vaše zpětná vazba nám pomáhá se zlepšovat + Jejda! Něco se pokazilo + Zkuste to prosím znovu + Jejda! To jsem nezachytil. + Žádné připojení + diff --git a/libnavui-voicefeedback/src/main/res/values-da/strings.xml b/libnavui-voicefeedback/src/main/res/values-da/strings.xml new file mode 100644 index 00000000000..7b80a0d4cc0 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-da/strings.xml @@ -0,0 +1,12 @@ + + + Del din feedback + Lytter… + Behandler… + Tak fordi du delte + Din feedback hjælper os med at blive bedre + Ups! Noget gik galt + Prøv venligst igen + Ups! Det fangede jeg ikke + Ingen forbindelse + diff --git a/libnavui-voicefeedback/src/main/res/values-de/strings.xml b/libnavui-voicefeedback/src/main/res/values-de/strings.xml new file mode 100644 index 00000000000..c3f1fd26f0b --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-de/strings.xml @@ -0,0 +1,12 @@ + + + Teilen Sie Ihr Feedback + Zuhören… + Verarbeitung… + Danke fürs Teilen + Ihr Feedback hilft uns, uns zu verbessern + Hoppla! Etwas ist schiefgelaufen + Bitte versuchen Sie es erneut + Hoppla! Das habe ich nicht verstanden + Keine Verbindung + diff --git a/libnavui-voicefeedback/src/main/res/values-el/strings.xml b/libnavui-voicefeedback/src/main/res/values-el/strings.xml new file mode 100644 index 00000000000..af29356f5ae --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-el/strings.xml @@ -0,0 +1,12 @@ + + + Μοιραστείτε τα σχόλιά σας + Ακρόαση… + Γίνεται επεξεργασία… + Ευχαριστώ που το μοιράστηκες + Τα σχόλιά σας μας βοηθούν να βελτιωνόμαστε + Ουπς! Κάτι πήγε στραβά + Παρακαλώ δοκιμάστε ξανά + Ουπς! Δεν το κατάλαβα αυτό + Χωρίς Σύνδεση + diff --git a/libnavui-voicefeedback/src/main/res/values-en-rAU/strings.xml b/libnavui-voicefeedback/src/main/res/values-en-rAU/strings.xml new file mode 100644 index 00000000000..4639bb4ed58 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-en-rAU/strings.xml @@ -0,0 +1,12 @@ + + + Share your feedback + Listening… + Processing… + Thanks for sharing + Your feedback helps us improve + Whoops! Something went wrong + Please try again + Whoops! Didn’t quite catch that + No Connection + diff --git a/libnavui-voicefeedback/src/main/res/values-en-rGB/strings.xml b/libnavui-voicefeedback/src/main/res/values-en-rGB/strings.xml new file mode 100644 index 00000000000..ece9c5ddb7b --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-en-rGB/strings.xml @@ -0,0 +1,12 @@ + + + Share your feedback + Listening… + Processing… + Thanks for sharing + Your feedback helps us to improve + Oops! Something went wrong + Please try again + Oops! Didn’t catch that + No Connection + diff --git a/libnavui-voicefeedback/src/main/res/values-en-rIN/strings.xml b/libnavui-voicefeedback/src/main/res/values-en-rIN/strings.xml new file mode 100644 index 00000000000..38fe6049264 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-en-rIN/strings.xml @@ -0,0 +1,12 @@ + + + अपना फीडबैक साझा करें + सुन रहे हैं… + प्रोसेसिंग… + Thank you for sharing. + Your feedback helps us improve + अरे! कुछ गड़बड़ हो गई है + कृपया फिर से प्रयास करें + अरे! वह समझ में नहीं आया + कोई कनेक्शन नहीं + diff --git a/libnavui-voicefeedback/src/main/res/values-en-rSG/strings.xml b/libnavui-voicefeedback/src/main/res/values-en-rSG/strings.xml new file mode 100644 index 00000000000..0154eb81ae4 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-en-rSG/strings.xml @@ -0,0 +1,12 @@ + + + Kongsi maklum balas anda + Sedang mendengar… + Sedang diproses… + Thanks for sharing + Your feedback helps us improve + Aiyo! Something went wrong lah + Please try again + Aiyo! Didn’t catch that leh + No Connection + diff --git a/libnavui-voicefeedback/src/main/res/values-en-rUS/strings.xml b/libnavui-voicefeedback/src/main/res/values-en-rUS/strings.xml new file mode 100644 index 00000000000..277595a9b99 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-en-rUS/strings.xml @@ -0,0 +1,12 @@ + + + Share your feedback + Listening… + Processing… + Thanks for sharing + Your feedback helps us improve + Oops! Something went wrong + Please try again + Oops! Didn’t catch that + No Connection + diff --git a/libnavui-voicefeedback/src/main/res/values-es-rES/strings.xml b/libnavui-voicefeedback/src/main/res/values-es-rES/strings.xml new file mode 100644 index 00000000000..1061d118fa5 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-es-rES/strings.xml @@ -0,0 +1,12 @@ + + + Comparte tus comentarios + Escuchando… + Procesando… + Gracias por compartir + Tus comentarios nos ayudan a mejorar + ¡Vaya! Algo salió mal + Por favor, inténtalo de nuevo + ¡Ups! No entendí eso + Sin conexión + diff --git a/libnavui-voicefeedback/src/main/res/values-es-rMX/strings.xml b/libnavui-voicefeedback/src/main/res/values-es-rMX/strings.xml new file mode 100644 index 00000000000..4d337a13b0b --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-es-rMX/strings.xml @@ -0,0 +1,12 @@ + + + Comparte tus comentarios + Escuchando… + Procesando… + Gracias por compartir + Tus comentarios nos ayudan a mejorar + ¡Ups! Algo salió mal + Por favor, inténtalo de nuevo + ¡Ups! No entendí eso + Sin conexión + diff --git a/libnavui-voicefeedback/src/main/res/values-es/strings.xml b/libnavui-voicefeedback/src/main/res/values-es/strings.xml new file mode 100644 index 00000000000..664f3725a5c --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-es/strings.xml @@ -0,0 +1,12 @@ + + + Comparte tus comentarios + Escuchando… + Procesando… + Gracias por compartir + Tus comentarios nos ayudan a mejorar + ¡Ups! Algo salió mal + Por favor intenta de nuevo + ¡Ups! No entendí eso + Sin conexión + diff --git a/libnavui-voicefeedback/src/main/res/values-et/strings.xml b/libnavui-voicefeedback/src/main/res/values-et/strings.xml new file mode 100644 index 00000000000..a0a1d5845e9 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-et/strings.xml @@ -0,0 +1,12 @@ + + + Jaga oma tagasisidet + Kuulan… + Töötlemine… + Aitäh jagamast + Teie tagasiside aitab meil paremaks saada + Oih! Midagi läks valesti + Palun proovige uuesti + Oih! Ei saanud sellest aru + Ühendus puudub + diff --git a/libnavui-voicefeedback/src/main/res/values-fi/strings.xml b/libnavui-voicefeedback/src/main/res/values-fi/strings.xml new file mode 100644 index 00000000000..01d884bfc2c --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-fi/strings.xml @@ -0,0 +1,12 @@ + + + Jaa palautteesi + Kuunnellaan… + Käsitellään… + Kiitos jakamisesta + Palautteesi auttaa meitä parantamaan toimintaamme + Hups! Jotain meni pieleen + Yritä uudelleen + Hups! En saanut siitä selvää + Ei yhteyttä + diff --git a/libnavui-voicefeedback/src/main/res/values-fr-rCA/strings.xml b/libnavui-voicefeedback/src/main/res/values-fr-rCA/strings.xml new file mode 100644 index 00000000000..5b83ee067f5 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-fr-rCA/strings.xml @@ -0,0 +1,12 @@ + + + Partagez vos commentaires + Écoute en cours… + Traitement en cours… + Merci pour le partage + Vos commentaires nous aident à nous améliorer + Oups ! Quelque chose s\'est mal passé + Veuillez réessayer + Oups ! Je n’ai pas compris. + Pas de connexion + diff --git a/libnavui-voicefeedback/src/main/res/values-fr/strings.xml b/libnavui-voicefeedback/src/main/res/values-fr/strings.xml new file mode 100644 index 00000000000..8b2bab11ff2 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-fr/strings.xml @@ -0,0 +1,12 @@ + + + Partagez vos commentaires + Écoute en cours… + Traitement en cours… + Merci pour le partage + Vos commentaires nous aident à nous améliorer + Oups ! Quelque chose s\'est mal passé + Veuillez réessayer + Oups ! Je n\'ai pas compris. + Pas de connexion + diff --git a/libnavui-voicefeedback/src/main/res/values-hr/strings.xml b/libnavui-voicefeedback/src/main/res/values-hr/strings.xml new file mode 100644 index 00000000000..95a49ffec6d --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-hr/strings.xml @@ -0,0 +1,12 @@ + + + Podijelite svoje povratne informacije + Slušanje… + Obrada… + Hvala što ste podijelili + Vaše povratne informacije pomažu nam da se poboljšamo + Ups! Nešto je pošlo po zlu + Pokušajte ponovno + Ups! Nisam to uhvatio/la + Nema veze + diff --git a/libnavui-voicefeedback/src/main/res/values-hu/strings.xml b/libnavui-voicefeedback/src/main/res/values-hu/strings.xml new file mode 100644 index 00000000000..8c18dbd1ebc --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-hu/strings.xml @@ -0,0 +1,12 @@ + + + Ossza meg visszajelzését + Hallgatás… + Feldolgozás… + Köszönöm, hogy megosztottad + Az Ön visszajelzése segít nekünk a fejlődésben + Hoppá! Valami hiba történt + Kérjük, próbálja meg újra + Hoppá! Ezt nem értettem. + Nincs kapcsolat + diff --git a/libnavui-voicefeedback/src/main/res/values-in/strings.xml b/libnavui-voicefeedback/src/main/res/values-in/strings.xml new file mode 100644 index 00000000000..8cd1e88f598 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-in/strings.xml @@ -0,0 +1,12 @@ + + + Bagikan masukan Anda + Mendengarkan… + Memproses… + Terima kasih sudah berbagi + Masukan Anda membantu kami untuk menjadi lebih baik + Ups! Terjadi kesalahan + Silakan coba lagi + Ups! Saya tidak menangkap itu + Tidak Ada Koneksi + diff --git a/libnavui-voicefeedback/src/main/res/values-is/strings.xml b/libnavui-voicefeedback/src/main/res/values-is/strings.xml new file mode 100644 index 00000000000..5c96252d2c2 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-is/strings.xml @@ -0,0 +1,12 @@ + + + Deildu ábendingum þínum + Hlusta… + Í vinnslu… + Takk fyrir að deila þessu + Endurgjöf þín hjálpar okkur að bæta þjónustuna. + Úbbs! Eitthvað fór úrskeiðis + Vinsamlegast reyndu aftur + Úbbs! Ég náði því ekki + Engin tenging + diff --git a/libnavui-voicefeedback/src/main/res/values-it/strings.xml b/libnavui-voicefeedback/src/main/res/values-it/strings.xml new file mode 100644 index 00000000000..0e4febd6757 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-it/strings.xml @@ -0,0 +1,12 @@ + + + Condividi il tuo feedback + In ascolto… + Elaborazione in corso… + Grazie per aver condiviso + Il tuo feedback ci aiuta a migliorare + Ops! Qualcosa è andato storto + Per favore riprova + Ops! Non ho capito + Nessuna connessione + diff --git a/libnavui-voicefeedback/src/main/res/values-iw/strings.xml b/libnavui-voicefeedback/src/main/res/values-iw/strings.xml new file mode 100644 index 00000000000..d3374829ae2 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-iw/strings.xml @@ -0,0 +1,12 @@ + + + שתפו את המשוב שלכם + מקשיב… + מעבד… + תודה ששיתפת + המשוב שלך עוזר לנו להשתפר + אופס! משהו השתבש + אנא נסה שוב + אופס! לא קלטתי את זה + אין חיבור + diff --git a/libnavui-voicefeedback/src/main/res/values-ja-rJP/strings.xml b/libnavui-voicefeedback/src/main/res/values-ja-rJP/strings.xml new file mode 100644 index 00000000000..901e88aab0b --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-ja-rJP/strings.xml @@ -0,0 +1,12 @@ + + + ご意見をお聞かせください + 聞き取り中… + 処理中… + 共有してくれてありがとうございます + ご意見は、私たちの改善に役立ちます。 + おっと!何か問題が発生しました + もう一度お試しください + おっと!聞き取れませんでした + 接続なし + diff --git a/libnavui-voicefeedback/src/main/res/values-ja/strings.xml b/libnavui-voicefeedback/src/main/res/values-ja/strings.xml new file mode 100644 index 00000000000..a2543c95525 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-ja/strings.xml @@ -0,0 +1,12 @@ + + + ご意見をお聞かせください + 聞き取り中… + 処理中… + 共有してくれてありがとうございます + あなたのフィードバックは、私たちの改善に役立ちます。 + おっと!何か問題が発生しました + もう一度お試しください + おっと!聞き取れませんでした + 接続なし + diff --git a/libnavui-voicefeedback/src/main/res/values-ko/strings.xml b/libnavui-voicefeedback/src/main/res/values-ko/strings.xml new file mode 100644 index 00000000000..b9cb50b60cb --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-ko/strings.xml @@ -0,0 +1,12 @@ + + + 의견을 공유해 주세요 + 듣는 중… + 처리 중… + 공유해 주셔서 감사합니다 + 귀하의 피드백은 저희가 개선하는 데 도움이 됩니다 + 이런! 문제가 발생했습니다 + 다시 시도해 주세요 + 이런! 잘 못 들었어요 + 연결 없음 + diff --git a/libnavui-voicefeedback/src/main/res/values-lt/strings.xml b/libnavui-voicefeedback/src/main/res/values-lt/strings.xml new file mode 100644 index 00000000000..45bf46817a8 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-lt/strings.xml @@ -0,0 +1,12 @@ + + + Pasidalinkite savo atsiliepimais + Klausoma… + Apdorojama… + Ačiū, kad pasidalinote + Jūsų atsiliepimai padeda mums tobulėti + Oi! Kažkas nepavyko + Pabandykite dar kartą + Oi! Nepagavau to + Nėra ryšio + diff --git a/libnavui-voicefeedback/src/main/res/values-lv/strings.xml b/libnavui-voicefeedback/src/main/res/values-lv/strings.xml new file mode 100644 index 00000000000..acf5716c236 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-lv/strings.xml @@ -0,0 +1,12 @@ + + + Dalieties ar savu atsauksmi + Klausās… + Notiek apstrāde… + Paldies, ka dalījāties + Jūsu atsauksmes palīdz mums uzlaboties + Ak! Kaut kas nogāja greizi + Lūdzu, mēģiniet vēlreiz + Ups! Nesapratu to + Nav savienojuma + diff --git a/libnavui-voicefeedback/src/main/res/values-ms/strings.xml b/libnavui-voicefeedback/src/main/res/values-ms/strings.xml new file mode 100644 index 00000000000..7ed30097ff8 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-ms/strings.xml @@ -0,0 +1,12 @@ + + + Kongsi maklum balas anda + Sedang mendengar… + Memproses… + Terima kasih kerana berkongsi + Maklum balas anda membantu kami untuk menambah baik + Oops! Sesuatu telah berlaku kesilapan + Sila cuba lagi + Oops! Tidak dapat menangkap itu + Tiada Sambungan + diff --git a/libnavui-voicefeedback/src/main/res/values-nb/strings.xml b/libnavui-voicefeedback/src/main/res/values-nb/strings.xml new file mode 100644 index 00000000000..c32d8d29d7b --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-nb/strings.xml @@ -0,0 +1,12 @@ + + + Del dine tilbakemeldinger + Lytter… + Behandler … + Takk for at du delte + Din tilbakemelding hjelper oss å bli bedre + Oops! Noe gikk galt + Vennligst prøv igjen + Oi! Fikk ikke med meg det + Ingen tilkobling + diff --git a/libnavui-voicefeedback/src/main/res/values-night/colors.xml b/libnavui-voicefeedback/src/main/res/values-night/colors.xml new file mode 100644 index 00000000000..51ca900bc4e --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-night/colors.xml @@ -0,0 +1,10 @@ + + + #181B20 + #292C33 + #EDEFF2 + #A6B2C6 + #EDEFF2 + #0BDA95 + #EA3136 + diff --git a/libnavui-voicefeedback/src/main/res/values-nl-rBE/strings.xml b/libnavui-voicefeedback/src/main/res/values-nl-rBE/strings.xml new file mode 100644 index 00000000000..558ba73583c --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-nl-rBE/strings.xml @@ -0,0 +1,12 @@ + + + Deel je feedback + Luisteren... + Bezig met verwerken… + Bedankt om dit te delen + Uw feedback helpt ons om te verbeteren + Oeps! Er is iets misgegaan + Probeer het opnieuw + Oeps! Dat heb ik niet begrepen + Geen verbinding + diff --git a/libnavui-voicefeedback/src/main/res/values-nl-rNL/strings.xml b/libnavui-voicefeedback/src/main/res/values-nl-rNL/strings.xml new file mode 100644 index 00000000000..a7437c6202e --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-nl-rNL/strings.xml @@ -0,0 +1,12 @@ + + + Deel je feedback + Luisteren... + Bezig met verwerken… + Bedankt voor het delen + Uw feedback helpt ons te verbeteren + Oeps! Er is iets misgegaan + Probeer het opnieuw + Oeps! Dat heb ik niet begrepen + Geen verbinding + diff --git a/libnavui-voicefeedback/src/main/res/values-nl/strings.xml b/libnavui-voicefeedback/src/main/res/values-nl/strings.xml new file mode 100644 index 00000000000..823c05765ae --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-nl/strings.xml @@ -0,0 +1,12 @@ + + + Deel uw feedback + Luisteren... + Bezig met verwerken… + Bedankt voor het delen + Uw feedback helpt ons te verbeteren + Oeps! Er is iets misgegaan + Probeer het opnieuw + Oeps! Dat heb ik niet begrepen + Geen verbinding + diff --git a/libnavui-voicefeedback/src/main/res/values-no-rNO/strings.xml b/libnavui-voicefeedback/src/main/res/values-no-rNO/strings.xml new file mode 100644 index 00000000000..999866676f7 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-no-rNO/strings.xml @@ -0,0 +1,12 @@ + + + Del tilbakemeldingen din + Lytter… + Behandler … + Takk for at du delte + Din tilbakemelding hjelper oss å bli bedre + Oi! Noe gikk galt + Prøv igjen + Uff da! Fikk ikke med meg det + Ingen tilkobling + diff --git a/libnavui-voicefeedback/src/main/res/values-pl/strings.xml b/libnavui-voicefeedback/src/main/res/values-pl/strings.xml new file mode 100644 index 00000000000..93f236725a5 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-pl/strings.xml @@ -0,0 +1,12 @@ + + + Podziel się swoją opinią + Słucham… + Przetwarzanie… + Dziękuję za udostępnienie + Twoja opinia pomaga nam się rozwijać + Ups! Coś poszło nie tak + Proszę spróbować ponownie + Ups! Nie zrozumiałem tego. + Brak połączenia + diff --git a/libnavui-voicefeedback/src/main/res/values-pt-rBR/strings.xml b/libnavui-voicefeedback/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 00000000000..e8f48d2f414 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,12 @@ + + + Compartilhe seu feedback + Ouvindo... + Processando… + Obrigado por compartilhar + Seu feedback nos ajuda a melhorar + Ops! Algo deu errado + Por favor, tente novamente + Ops! Não entendi isso + Sem Conexão + diff --git a/libnavui-voicefeedback/src/main/res/values-pt/strings.xml b/libnavui-voicefeedback/src/main/res/values-pt/strings.xml new file mode 100644 index 00000000000..e8f48d2f414 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-pt/strings.xml @@ -0,0 +1,12 @@ + + + Compartilhe seu feedback + Ouvindo... + Processando… + Obrigado por compartilhar + Seu feedback nos ajuda a melhorar + Ops! Algo deu errado + Por favor, tente novamente + Ops! Não entendi isso + Sem Conexão + diff --git a/libnavui-voicefeedback/src/main/res/values-ro/strings.xml b/libnavui-voicefeedback/src/main/res/values-ro/strings.xml new file mode 100644 index 00000000000..010d76a28d8 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-ro/strings.xml @@ -0,0 +1,12 @@ + + + Trimiteți feedback-ul dvs. + Ascultare… + Se procesează… + Mulțumesc că ai împărtășit + Feedback-ul dumneavoastră ne ajută să ne îmbunătățim + Ups! Ceva nu a mers bine + Vă rugăm să încercați din nou + Ups! Nu am prins asta + Fără conexiune + diff --git a/libnavui-voicefeedback/src/main/res/values-ru/strings.xml b/libnavui-voicefeedback/src/main/res/values-ru/strings.xml new file mode 100644 index 00000000000..d6c83a23740 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-ru/strings.xml @@ -0,0 +1,12 @@ + + + Поделитесь своим мнением + Прослушивание… + Обработка… + Спасибо за то, что поделились + Ваш отзыв помогает нам совершенствоваться + Ой! Что-то пошло не так + Пожалуйста, попробуйте еще раз + Ой! Не расслышал + Нет подключения + diff --git a/libnavui-voicefeedback/src/main/res/values-sk/strings.xml b/libnavui-voicefeedback/src/main/res/values-sk/strings.xml new file mode 100644 index 00000000000..2ef807a0d08 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-sk/strings.xml @@ -0,0 +1,12 @@ + + + Podeľte sa o svoju spätnú väzbu + Počúvam… + Spracováva sa… + Ďakujeme za zdieľanie + Vaša spätná väzba nám pomáha zlepšovať sa + Ups! Niečo sa pokazilo + Skúste to prosím znova + Ups! Nezachytil som to + Žiadne pripojenie + diff --git a/libnavui-voicefeedback/src/main/res/values-sl/strings.xml b/libnavui-voicefeedback/src/main/res/values-sl/strings.xml new file mode 100644 index 00000000000..281fc5d6f5f --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-sl/strings.xml @@ -0,0 +1,12 @@ + + + Delite svoje mnenje + Poslušanje… + Obdelava … + Hvala, da ste delili + Vaše povratne informacije nam pomagajo izboljšati naše storitve + Ups! Nekaj je šlo narobe + Poskusite znova + Ups! Tega nisem razumel + Ni povezave + diff --git a/libnavui-voicefeedback/src/main/res/values-sq/strings.xml b/libnavui-voicefeedback/src/main/res/values-sq/strings.xml new file mode 100644 index 00000000000..d66e70ac6c4 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-sq/strings.xml @@ -0,0 +1,12 @@ + + + Ndani mendimet tuaja + Duke dëgjuar… + Duke përpunuar… + Faleminderit që e ndave + Mendimet tuaja na ndihmojnë të përmirësohemi + Ups! Diçka shkoi keq + Ju lutemi provoni përsëri + Ups! Nuk e kapa atë + Pa lidhje + diff --git a/libnavui-voicefeedback/src/main/res/values-sr/strings.xml b/libnavui-voicefeedback/src/main/res/values-sr/strings.xml new file mode 100644 index 00000000000..03685abb217 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-sr/strings.xml @@ -0,0 +1,12 @@ + + + Podelite svoje mišljenje + Слушање… + Обрада… + Hvala što ste podelili + Vaše povratne informacije nam pomažu da se poboljšamo + Упс! Нешто је пошло наопако + Pokušajte ponovo + Ups! Nisam to uhvatio. + Nema veze + diff --git a/libnavui-voicefeedback/src/main/res/values-sv/strings.xml b/libnavui-voicefeedback/src/main/res/values-sv/strings.xml new file mode 100644 index 00000000000..45528620410 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-sv/strings.xml @@ -0,0 +1,12 @@ + + + Dela din feedback + Lyssnar… + Bearbetar… + Tack för att du delade med dig + Din feedback hjälper oss att bli bättre + Hoppsan! Något gick fel + Var god försök igen + Hoppsan! Det uppfattade jag inte + Ingen anslutning + diff --git a/libnavui-voicefeedback/src/main/res/values-sw600dp-land/dimens.xml b/libnavui-voicefeedback/src/main/res/values-sw600dp-land/dimens.xml new file mode 100644 index 00000000000..3be3c2a351d --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-sw600dp-land/dimens.xml @@ -0,0 +1,30 @@ + + + + 90dp + 40dp + + + 540dp + 24dp + 12dp + + + 24dp + + + 60dp + 36dp + + + 32sp + 160dp + 28sp + 12dp + + + 80dp + 20dp + 8dp + 14dp + diff --git a/libnavui-voicefeedback/src/main/res/values-sw600dp/bools.xml b/libnavui-voicefeedback/src/main/res/values-sw600dp/bools.xml new file mode 100644 index 00000000000..5fc3a0d0dfa --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-sw600dp/bools.xml @@ -0,0 +1,4 @@ + + + true + \ No newline at end of file diff --git a/libnavui-voicefeedback/src/main/res/values-th/strings.xml b/libnavui-voicefeedback/src/main/res/values-th/strings.xml new file mode 100644 index 00000000000..14647b675ca --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-th/strings.xml @@ -0,0 +1,12 @@ + + + แบ่งปันความคิดเห็นของคุณ + กำลังฟัง... + กำลังประมวลผล… + ขอบคุณที่แบ่งปัน + ความคิดเห็นของคุณช่วยให้เราพัฒนาขึ้น + ขออภัย! เกิดข้อผิดพลาดบางอย่าง + กรุณาลองใหม่อีกครั้ง + อุ๊ย! ฟังไม่ทันค่ะ + ไม่มีการเชื่อมต่อ + diff --git a/libnavui-voicefeedback/src/main/res/values-tr/strings.xml b/libnavui-voicefeedback/src/main/res/values-tr/strings.xml new file mode 100644 index 00000000000..4770c394808 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-tr/strings.xml @@ -0,0 +1,12 @@ + + + Görüşlerinizi paylaşın + Dinleniyor… + İşleniyor… + Paylaştığınız için teşekkürler + Geri bildiriminiz bize gelişmemizde yardımcı oluyor + Hata! Bir şeyler ters gitti + Lütfen tekrar deneyin + Hata! Bunu anlayamadım + Bağlantı Yok + diff --git a/libnavui-voicefeedback/src/main/res/values-uk/strings.xml b/libnavui-voicefeedback/src/main/res/values-uk/strings.xml new file mode 100644 index 00000000000..1e84acc2e0f --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-uk/strings.xml @@ -0,0 +1,12 @@ + + + Поділіться своїми відгуками + Слухаю… + Обробка… + Дякую, що поділилися + Ваш відгук допомагає нам ставати кращими + Ой! Щось пішло не так + Будь ласка, спробуйте ще раз + Ой! Не зрозумів(ла) цього + Немає з\'єднання + diff --git a/libnavui-voicefeedback/src/main/res/values-vi/strings.xml b/libnavui-voicefeedback/src/main/res/values-vi/strings.xml new file mode 100644 index 00000000000..d8900a2871a --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-vi/strings.xml @@ -0,0 +1,12 @@ + + + Chia sẻ phản hồi của bạn + Đang lắng nghe… + Đang xử lý… + Cảm ơn bạn đã chia sẻ + Phản hồi của bạn giúp chúng tôi cải thiện + Ôi! Đã xảy ra sự cố + Vui lòng thử lại + Ôi! Tôi không nghe rõ điều đó + Không có kết nối + diff --git a/libnavui-voicefeedback/src/main/res/values-zh-rCN/strings.xml b/libnavui-voicefeedback/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 00000000000..e9ee4feb873 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,12 @@ + + + 分享您的反馈 + 正在聆听… + 处理中… + 感谢分享 + 您的反馈有助于我们改进 + 哎呀!出了点问题 + 请再试一次 + 哎呀!没听清楚 + 无连接 + diff --git a/libnavui-voicefeedback/src/main/res/values-zh-rHK/strings.xml b/libnavui-voicefeedback/src/main/res/values-zh-rHK/strings.xml new file mode 100644 index 00000000000..d835cbc6cb0 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-zh-rHK/strings.xml @@ -0,0 +1,12 @@ + + + 分享你的意見 + 正在聆聽… + 處理中… + 多謝分享 + 您的意見有助我們改進 + 哎呀!出現了一些問題 + 請再試一次 + 哎呀!我聽唔清楚你講咩 + 無連接 + diff --git a/libnavui-voicefeedback/src/main/res/values-zh-rTW/strings.xml b/libnavui-voicefeedback/src/main/res/values-zh-rTW/strings.xml new file mode 100644 index 00000000000..e393314b135 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values-zh-rTW/strings.xml @@ -0,0 +1,12 @@ + + + 分享您的意見 + 聆聽中… + 處理中… + 感謝分享 + 您的回饋幫助我們改進 + 哎呀!出了點問題 + 請再試一次 + 哎呀!沒聽清楚 + 無連線 + diff --git a/libnavui-voicefeedback/src/main/res/values/attrs.xml b/libnavui-voicefeedback/src/main/res/values/attrs.xml new file mode 100644 index 00000000000..6c99fc09670 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values/attrs.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/libnavui-voicefeedback/src/main/res/values/bools.xml b/libnavui-voicefeedback/src/main/res/values/bools.xml new file mode 100644 index 00000000000..84d7d2f5cf2 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values/bools.xml @@ -0,0 +1,4 @@ + + + false + \ No newline at end of file diff --git a/libnavui-voicefeedback/src/main/res/values/colors.xml b/libnavui-voicefeedback/src/main/res/values/colors.xml new file mode 100644 index 00000000000..f53c296e5f0 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values/colors.xml @@ -0,0 +1,11 @@ + + + #FFFFFF + #F2F4F7 + #05070A + #536275 + #23262D + #3072F5 + #09AA74 + #EB252A + diff --git a/libnavui-voicefeedback/src/main/res/values/dimens.xml b/libnavui-voicefeedback/src/main/res/values/dimens.xml new file mode 100644 index 00000000000..79ec458700d --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values/dimens.xml @@ -0,0 +1,30 @@ + + + + 60dp + 28dp + + + 340dp + 16dp + 8dp + + + 16dp + + + 40dp + 32dp + + + 20sp + 120dp + 18sp + 4dp + + + 48dp + 16dp + 4dp + 16dp + diff --git a/libnavui-voicefeedback/src/main/res/values/strings.xml b/libnavui-voicefeedback/src/main/res/values/strings.xml new file mode 100644 index 00000000000..80d021de80a --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values/strings.xml @@ -0,0 +1,12 @@ + + + Share your feedback + Listening… + Processing… + Thanks for sharing + Your feedback helps us improve + Oops! Something went wrong + Please try again + Oops! Didn’t catch that + No Connection + \ No newline at end of file diff --git a/libnavui-voicefeedback/src/main/res/values/styles.xml b/libnavui-voicefeedback/src/main/res/values/styles.xml new file mode 100644 index 00000000000..3fb01622607 --- /dev/null +++ b/libnavui-voicefeedback/src/main/res/values/styles.xml @@ -0,0 +1,19 @@ + + + + + + + + \ No newline at end of file diff --git a/libnavui-voicefeedback/src/test/java/com/mapbox/navigation/ui/voicefeedback/view/MapboxVoiceFeedbackDialogTest.kt b/libnavui-voicefeedback/src/test/java/com/mapbox/navigation/ui/voicefeedback/view/MapboxVoiceFeedbackDialogTest.kt new file mode 100644 index 00000000000..0d3b9ee85df --- /dev/null +++ b/libnavui-voicefeedback/src/test/java/com/mapbox/navigation/ui/voicefeedback/view/MapboxVoiceFeedbackDialogTest.kt @@ -0,0 +1,86 @@ +package com.mapbox.navigation.ui.voicefeedback.view + +import androidx.fragment.app.FragmentActivity +import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI +import com.mapbox.navigation.voicefeedback.ASRState +import com.mapbox.navigation.voicefeedback.FeedbackAgentSession +import io.mockk.Runs +import io.mockk.every +import io.mockk.just +import io.mockk.mockk +import io.mockk.mockkConstructor +import io.mockk.unmockkConstructor +import io.mockk.verify +import kotlinx.coroutines.flow.MutableStateFlow +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.Robolectric +import org.robolectric.RobolectricTestRunner +import org.robolectric.Shadows +import org.robolectric.android.controller.ActivityController + +@OptIn(ExperimentalPreviewMapboxNavigationAPI::class) +@RunWith(RobolectricTestRunner::class) +class MapboxVoiceFeedbackDialogTest { + + private lateinit var activityController: ActivityController + private lateinit var mockSession: FeedbackAgentSession + private lateinit var asrStateFlow: MutableStateFlow + + @Before + fun setUp() { + mockkConstructor(FeedbackAgentSession.Builder::class) + asrStateFlow = MutableStateFlow(ASRState.Idle) + val builder = mockk() + mockSession = mockk(relaxUnitFun = true) + every { mockSession.asrState } returns asrStateFlow + every { anyConstructed().build() } returns mockSession + every { anyConstructed().options(any()) } returns builder + every { builder.options(any()) } returns builder + every { builder.build() } returns mockSession + + activityController = Robolectric.buildActivity(FragmentActivity::class.java) + activityController.create().start().resume() + } + + @After + fun tearDown() { + activityController.pause().stop().destroy() + unmockkConstructor(FeedbackAgentSession.Builder::class) + } + + @Test + fun `startListening not called when session already in non-idle state`() { + asrStateFlow.value = ASRState.Listening("test") + every { mockSession.startListening() } just Runs + + val activity = activityController.get() + MapboxVoiceFeedbackDialog().show( + activity.supportFragmentManager, + MapboxVoiceFeedbackDialog.TAG + ) + + // startListening should NOT be called because current state is Listening, not Idle + verify(exactly = 0) { mockSession.startListening() } + } + + @Test + fun `startListening called when session is in idle state`() { + asrStateFlow.value = ASRState.Idle + every { mockSession.startListening() } just Runs + + val activity = activityController.get() + MapboxVoiceFeedbackDialog().show( + activity.supportFragmentManager, + MapboxVoiceFeedbackDialog.TAG + ) + + // Advance main looper to let coroutine execute + Shadows.shadowOf(activity.mainLooper).idle() + + // startListening should be called because current state is Idle + verify { mockSession.startListening() } + } +} diff --git a/libnavui-voicefeedback/src/test/java/com/mapbox/navigation/ui/voicefeedback/view/VoiceFeedbackViewModelTest.kt b/libnavui-voicefeedback/src/test/java/com/mapbox/navigation/ui/voicefeedback/view/VoiceFeedbackViewModelTest.kt new file mode 100644 index 00000000000..e4d277f5d19 --- /dev/null +++ b/libnavui-voicefeedback/src/test/java/com/mapbox/navigation/ui/voicefeedback/view/VoiceFeedbackViewModelTest.kt @@ -0,0 +1,69 @@ +package com.mapbox.navigation.ui.voicefeedback.view + +import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI +import com.mapbox.navigation.core.MapboxNavigation +import com.mapbox.navigation.voicefeedback.FeedbackAgentSession +import io.mockk.Runs +import io.mockk.every +import io.mockk.just +import io.mockk.mockk +import io.mockk.mockkConstructor +import io.mockk.unmockkConstructor +import io.mockk.verify +import org.junit.After +import org.junit.Before +import org.junit.Test + +@OptIn(ExperimentalPreviewMapboxNavigationAPI::class) +class VoiceFeedbackViewModelTest { + + private lateinit var viewModel: VoiceFeedbackViewModel + private lateinit var mockSession: FeedbackAgentSession + + @Before + fun setUp() { + mockkConstructor(FeedbackAgentSession.Builder::class) + val builder = mockk() + mockSession = mockk(relaxUnitFun = true) + every { anyConstructed().build() } returns mockSession + every { anyConstructed().options(any()) } returns builder + every { builder.options(any()) } returns builder + every { builder.build() } returns mockSession + + viewModel = VoiceFeedbackViewModel() + } + + @After + fun tearDown() { + unmockkConstructor(FeedbackAgentSession.Builder::class) + } + + @Test + fun `attach calls session onAttached and connect`() { + every { mockSession.onAttached(any()) } just Runs + every { mockSession.connect() } just Runs + val mapboxNavigation = mockk(relaxed = true) + + viewModel.attach(mapboxNavigation) + + verify { mockSession.onAttached(mapboxNavigation) } + verify { mockSession.connect() } + } + + @Test + fun `detach calls session onDetached`() { + every { mockSession.onDetached(any()) } just Runs + val mapboxNavigation = mockk(relaxed = true) + + viewModel.detach(mapboxNavigation) + + verify { mockSession.onDetached(mapboxNavigation) } + } + + @Test + fun `session is created and accessible`() { + val session = viewModel.session + + assert(session === mockSession) + } +} diff --git a/libnavui-voicefeedback/src/test/resources/robolectric.properties b/libnavui-voicefeedback/src/test/resources/robolectric.properties new file mode 100644 index 00000000000..932b01b9ebc --- /dev/null +++ b/libnavui-voicefeedback/src/test/resources/robolectric.properties @@ -0,0 +1 @@ +sdk=28 diff --git a/settings.gradle b/settings.gradle index 64af2a73a9f..8d0544e0219 100644 --- a/settings.gradle +++ b/settings.gradle @@ -22,6 +22,7 @@ include ':examples', ':libnavui-maneuver', ':libnavui-resources', ':libnavui-voice', + ':libnavui-voicefeedback', ':libnavui-speedlimit', ':libnavui-shield', ':libnavui-status',