From ddbd4e7af6593fe1492611dbc4b61d12b7b35015 Mon Sep 17 00:00:00 2001 From: Kyle Madsen Date: Thu, 15 Sep 2022 14:26:58 -0700 Subject: [PATCH 1/6] Update audio guidance for AA compatibility --- CHANGELOG.md | 1 + LICENSE.md | 346 +----------------- libnavui-androidauto/CHANGELOG.md | 1 + libnavui-androidauto/api/current.txt | 4 +- libnavui-androidauto/build.gradle | 7 +- .../com/mapbox/androidauto/MapboxCarApp.kt | 20 +- .../audioguidance/AppAudioGuidanceUi.kt | 6 +- .../audioguidance/CarAudioGuidanceUi.kt | 2 +- .../navigation/ui/app/internal/SharedApp.kt | 22 +- .../AudioGuidanceStateController.kt | 4 +- .../AudioGuidanceStateControllerTest.kt | 23 +- .../navigation/dropin/NavigationView.kt | 3 +- libnavui-voice/api/current.txt | 21 ++ .../MapboxAudioGuidance.kt} | 83 +++-- .../ui/voice/api/MapboxAudioGuidanceState.kt | 74 ++++ .../ui/voice/installer/ComponentInstaller.kt | 11 +- .../ui/voice/internal/MapboxAudioGuidance.kt | 68 ---- .../internal/MapboxAudioGuidanceServices.kt | 20 - ...Impl.kt => MapboxAudioGuidanceServices.kt} | 19 +- .../ui/AudioGuidanceButtonComponent.kt | 4 +- .../voice/TestMapboxAudioGuidanceServices.kt | 17 +- .../MapboxAudioGuidanceTest.kt} | 67 ++-- .../ui/AudioGuidanceButtonComponentTest.kt | 18 +- .../qa_test_app/QaTestApplication.kt | 10 +- .../qa_test_app/car/MainCarSession.kt | 2 + 25 files changed, 250 insertions(+), 603 deletions(-) rename libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/{internal/impl/MapboxAudioGuidanceImpl.kt => api/MapboxAudioGuidance.kt} (74%) create mode 100644 libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidanceState.kt delete mode 100644 libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/MapboxAudioGuidance.kt delete mode 100644 libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/MapboxAudioGuidanceServices.kt rename libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/impl/{MapboxAudioGuidanceServicesImpl.kt => MapboxAudioGuidanceServices.kt} (71%) rename libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/{internal/impl/MapboxAudioGuidanceImplTest.kt => api/MapboxAudioGuidanceTest.kt} (79%) diff --git a/CHANGELOG.md b/CHANGELOG.md index d82d9823417..383d28adffa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Mapbox welcomes participation and contributions from everyone. ## Unreleased #### Features +- Moved `MapboxAudioGuidance` and `MapboxAudioGuidanceState` into public api. [#6336](https://github.com/mapbox/mapbox-navigation-android/pull/6336) #### Bug fixes and improvements ## Mapbox Navigation SDK 2.9.0-alpha.2 - 16 September, 2022 diff --git a/LICENSE.md b/LICENSE.md index 8b85c89861a..5d2606d6ca8 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -4021,12 +4021,6 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== -Mapbox Navigation uses portions of the Activity Kotlin Extensions (Kotlin extensions for 'activity' artifact). -URL: [https://developer.android.com/jetpack/androidx/releases/activity#1.2.3](https://developer.android.com/jetpack/androidx/releases/activity#1.2.3) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the Android App Startup Runtime. URL: [https://developer.android.com/jetpack/androidx/releases/startup#1.1.1](https://developer.android.com/jetpack/androidx/releases/startup#1.1.1) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4063,24 +4057,6 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== -Mapbox Navigation uses portions of the Android DataStore (Android DataStore - contains the underlying store used by each serialization method along with components that require an Android dependency). -URL: [https://developer.android.com/jetpack/androidx/releases/datastore#1.0.0](https://developer.android.com/jetpack/androidx/releases/datastore#1.0.0) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - -Mapbox Navigation uses portions of the Android DataStore Core (Android DataStore Core - contains the underlying store used by each serialization method). -URL: [https://developer.android.com/jetpack/androidx/releases/datastore#1.0.0](https://developer.android.com/jetpack/androidx/releases/datastore#1.0.0) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - -Mapbox Navigation uses portions of the Android DB. -URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the Android for Cars App Library (Build navigation, parking, and charging apps for Android Auto). URL: [https://developer.android.com/jetpack/androidx/releases/car-app#1.1.0](https://developer.android.com/jetpack/androidx/releases/car-app#1.1.0) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4111,24 +4087,12 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== -Mapbox Navigation uses portions of the Android Lifecycle Service. -URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the Android Lifecycle ViewModel. URL: [https://developer.android.com/jetpack/androidx/releases/lifecycle#2.3.1](https://developer.android.com/jetpack/androidx/releases/lifecycle#2.3.1) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== -Mapbox Navigation uses portions of the Android Lifecycle ViewModel Kotlin Extensions (Kotlin extensions for 'viewmodel' artifact). -URL: [https://developer.android.com/jetpack/androidx/releases/lifecycle#2.3.1](https://developer.android.com/jetpack/androidx/releases/lifecycle#2.3.1) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the Android Lifecycle ViewModel with SavedState (Android Lifecycle ViewModel). URL: [https://developer.android.com/jetpack/androidx/releases/lifecycle#2.3.1](https://developer.android.com/jetpack/androidx/releases/lifecycle#2.3.1) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4147,48 +4111,18 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== -Mapbox Navigation uses portions of the Android Preferences DataStore. -URL: [https://developer.android.com/jetpack/androidx/releases/datastore#1.0.0](https://developer.android.com/jetpack/androidx/releases/datastore#1.0.0) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - -Mapbox Navigation uses portions of the Android Preferences DataStore Core (Android Preferences DataStore without the Android Dependencies). -URL: [https://developer.android.com/jetpack/androidx/releases/datastore#1.0.0](https://developer.android.com/jetpack/androidx/releases/datastore#1.0.0) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the Android Resources Library (The Resources Library is a static library that you can add to your Android application in order to use resource APIs that backport the latest APIs to older versions of the platform. Compatible on devices running API 14 or later.). URL: [https://developer.android.com/jetpack/androidx/releases/appcompat#1.3.1](https://developer.android.com/jetpack/androidx/releases/appcompat#1.3.1) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== -Mapbox Navigation uses portions of the Android Room-Common. -URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - -Mapbox Navigation uses portions of the Android Room-Runtime. -URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the Android Support AnimatedVectorDrawable. URL: [https://developer.android.com/jetpack/androidx](https://developer.android.com/jetpack/androidx) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== -Mapbox Navigation uses portions of the Android Support CardView v7. -URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the Android Support ExifInterface. URL: [https://developer.android.com/jetpack/androidx](https://developer.android.com/jetpack/androidx) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4213,18 +4147,6 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== -Mapbox Navigation uses portions of the Android Support Library Coordinator Layout (The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.). -URL: [https://developer.android.com/jetpack/androidx](https://developer.android.com/jetpack/androidx) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - -Mapbox Navigation uses portions of the Android Support Library core utils (The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.). -URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the Android Support Library Cursor Adapter (The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.). URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4237,12 +4159,6 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== -Mapbox Navigation uses portions of the Android Support Library Document File (The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.). -URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the Android Support Library Drawer Layout (The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.). URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4250,7 +4166,7 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== Mapbox Navigation uses portions of the Android Support Library fragment (The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.). -URL: [https://developer.android.com/jetpack/androidx/releases/fragment#1.4.0](https://developer.android.com/jetpack/androidx/releases/fragment#1.4.0) +URL: [https://developer.android.com/jetpack/androidx/releases/fragment#1.3.6](https://developer.android.com/jetpack/androidx/releases/fragment#1.3.6) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== @@ -4267,36 +4183,12 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== -Mapbox Navigation uses portions of the Android Support Library Local Broadcast Manager (The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.). -URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - -Mapbox Navigation uses portions of the Android Support Library Print (The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.). -URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the Android Support Library View Pager (The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.). URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== -Mapbox Navigation uses portions of the Android Support RecyclerView v7. -URL: [https://developer.android.com/jetpack/androidx](https://developer.android.com/jetpack/androidx) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - -Mapbox Navigation uses portions of the Android Support SQLite - Framework Implementation (The implementation of Support SQLite library using the framework code.). -URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the Android Support VectorDrawable. URL: [https://developer.android.com/jetpack/androidx](https://developer.android.com/jetpack/androidx) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4309,58 +4201,18 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== -Mapbox Navigation uses portions of the Android Transition Support Library. -URL: [https://developer.android.com/jetpack/androidx](https://developer.android.com/jetpack/androidx) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - -Mapbox Navigation uses portions of the Android WorkManager Runtime (Android WorkManager runtime library). -URL: [https://developer.android.com/jetpack/androidx/releases/work#2.7.1](https://developer.android.com/jetpack/androidx/releases/work#2.7.1) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - -Mapbox Navigation uses portions of the AndroidSVG (SVG rendering library for Android.). -URL: [https://github.com/BigBadaboom/androidsvg](https://github.com/BigBadaboom/androidsvg) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the AndroidX Futures (Androidx implementation of Guava's ListenableFuture). URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== -Mapbox Navigation uses portions of the AndroidX Widget ViewPager2. -URL: [https://developer.android.com/jetpack/androidx](https://developer.android.com/jetpack/androidx) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - -Mapbox Navigation uses portions of the auto-value-gson-runtime. -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - -Mapbox Navigation uses portions of the autotransient (A transient annotation for AutoValue extensions.). -URL: [https://github.com/ZacSweers/AutoTransient/](https://github.com/ZacSweers/AutoTransient/) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the Collections Kotlin Extensions (Kotlin extensions for 'collection' artifact). URL: [https://developer.android.com/jetpack/androidx/releases/collection#1.2.0](https://developer.android.com/jetpack/androidx/releases/collection#1.2.0) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== -Mapbox Navigation uses portions of the Converter: Gson. -License: [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the Core Kotlin Extensions (Kotlin extensions for 'core' artifact). URL: [https://developer.android.com/jetpack/androidx/releases/core#1.7.0](https://developer.android.com/jetpack/androidx/releases/core#1.7.0) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4373,12 +4225,6 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== -Mapbox Navigation uses portions of the Fragment Kotlin Extensions (Kotlin extensions for 'fragment' artifact). -URL: [https://developer.android.com/jetpack/androidx/releases/fragment#1.4.0](https://developer.android.com/jetpack/androidx/releases/fragment#1.4.0) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the Glide (A fast and efficient image loading library for Android focused on smooth scrolling.). URL: [https://github.com/bumptech/glide](https://github.com/bumptech/glide) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4501,18 +4347,6 @@ License: [Mapbox Terms of Service](https://www.mapbox.com/legal/tos) =========================================================================== -Mapbox Navigation uses portions of the Mapbox Android Core SDK. -URL: [https://github.com/mapbox/mapbox-sdk](https://github.com/mapbox/mapbox-sdk) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - -Mapbox Navigation uses portions of the Mapbox Android Gestures Library. -URL: [https://github.com/mapbox/mapbox-gestures-android](https://github.com/mapbox/mapbox-gestures-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - Mapbox Navigation uses portions of the Mapbox Android Telemetry Core (Mapbox Android Core Library). URL: [https://github.com/mapbox/mapbox-events-android](https://github.com/mapbox/mapbox-events-android) License: [MIT](https://mit-license.org) @@ -4537,12 +4371,6 @@ License: [BSD](https://opensource.org/licenses/BSD-2-Clause) =========================================================================== -Mapbox Navigation uses portions of the Mapbox Hybrid Router (Artifact that provides the default implementation of the routing engine implementation that alternates between offbaord and onboard data (online/offline)). -URL: [https://github.com/mapbox/mapbox-navigation-android](https://github.com/mapbox/mapbox-navigation-android) -License: [Mapbox Terms of Service](https://www.mapbox.com/legal/tos/) - -=========================================================================== - Mapbox Navigation uses portions of the Mapbox Java SDK. URL: [https://github.com/mapbox/mapbox-java](https://github.com/mapbox/mapbox-java) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4561,60 +4389,6 @@ License: [BSD](https://opensource.org/licenses/BSD-2-Clause) =========================================================================== -Mapbox Navigation uses portions of the Mapbox Maps SDK. -URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - -Mapbox Navigation uses portions of the Mapbox Maps SDK Base. -URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - -Mapbox Navigation uses portions of the Mapbox Navigation Base (Artifact that provides the set of interface definitions and DTOs used in the modular Navigation SDK). -URL: [https://github.com/mapbox/mapbox-navigation-android](https://github.com/mapbox/mapbox-navigation-android) -License: [Mapbox Terms of Service](https://www.mapbox.com/legal/tos/) - -=========================================================================== - -Mapbox Navigation uses portions of the Mapbox Navigation Metrics (Artifact that provides the default implementation of the metrics integration). -URL: [https://github.com/mapbox/mapbox-navigation-android](https://github.com/mapbox/mapbox-navigation-android) -License: [Mapbox Terms of Service](https://www.mapbox.com/legal/tos/) - -=========================================================================== - -Mapbox Navigation uses portions of the Mapbox Navigation Native (Common multi-platform navigation logic). -URL: [https://github.com/mapbox/mapbox-navigation-native](https://github.com/mapbox/mapbox-navigation-native) -License: [Mapbox Terms of Service](https://www.mapbox.com/tos) - -=========================================================================== - -Mapbox Navigation uses portions of the Mapbox Navigation Native wrapper (Artifact that provides the native capabilities of the SDK). -URL: [https://github.com/mapbox/mapbox-navigation-android](https://github.com/mapbox/mapbox-navigation-android) -License: [Mapbox Terms of Service](https://www.mapbox.com/legal/tos/) - -=========================================================================== - -Mapbox Navigation uses portions of the Mapbox Navigation Notification (Artifact that provides the default implementation of the navigation notification). -URL: [https://github.com/mapbox/mapbox-navigation-android](https://github.com/mapbox/mapbox-navigation-android) -License: [Mapbox Terms of Service](https://www.mapbox.com/legal/tos/) - -=========================================================================== - -Mapbox Navigation uses portions of the Mapbox Navigation SDK (Artifact that groups all of the Navigation SDK features). -URL: [https://github.com/mapbox/mapbox-navigation-android](https://github.com/mapbox/mapbox-navigation-android) -License: [Mapbox Terms of Service](https://www.mapbox.com/legal/tos/) - -=========================================================================== - -Mapbox Navigation uses portions of the Mapbox Navigation Utils (Artifact that provides basic navigation utilities). -URL: [https://github.com/mapbox/mapbox-navigation-android](https://github.com/mapbox/mapbox-navigation-android) -License: [Mapbox Terms of Service](https://www.mapbox.com/legal/tos/) - -=========================================================================== - Mapbox Navigation uses portions of the Mapbox Search Native SDK for Android. URL: [https://github.com/mapbox/mapbox-search-android](https://github.com/mapbox/mapbox-search-android) License: [Mapbox Terms of Service](https://www.mapbox.com/legal/tos) @@ -4633,30 +4407,12 @@ License: [Mapbox Terms of Service](https://www.mapbox.com/legal/tos) =========================================================================== -Mapbox Navigation uses portions of the Mapbox Telemetry for Android (Mapbox Android Telemetry Library). -URL: [https://github.com/mapbox/mapbox-events-android](https://github.com/mapbox/mapbox-events-android) -License: [MIT](https://mit-license.org) - -=========================================================================== - -Mapbox Navigation uses portions of the Material Components for Android (Material Components for Android is a static library that you can add to your Android application in order to use APIs that provide implementations of the Material Design specification. Compatible on devices running API 14 or later.). -URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the okhttp (Square’s meticulous HTTP client for Java and Kotlin.). URL: [https://square.github.io/okhttp/](https://square.github.io/okhttp/) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== -Mapbox Navigation uses portions of the okhttp-logging-interceptor (Square’s meticulous HTTP client for Java and Kotlin.). -URL: [https://square.github.io/okhttp/](https://square.github.io/okhttp/) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox Navigation uses portions of the Okio (A modern I/O API for Java). URL: [https://github.com/square/okio/](https://github.com/square/okio/) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4669,118 +4425,18 @@ License: [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENS =========================================================================== -Mapbox Navigation uses portions of the Retrofit. -License: [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - -Mapbox Navigation uses portions of the SavedState Kotlin Extensions (Kotlin extensions for 'savedstate' artifact). -URL: [https://developer.android.com/jetpack/androidx/releases/savedstate#1.1.0](https://developer.android.com/jetpack/androidx/releases/savedstate#1.1.0) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - -Mapbox Navigation uses portions of the Telemetry for the Mapbox Maps SDK. -URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - Mapbox Navigation uses portions of the The android auto extension for the Mapbox Maps SDK for Android. URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) License: [BSD](https://opensource.org/licenses/BSD-2-Clause) =========================================================================== -Mapbox Navigation uses portions of the The annotation module for the Mapbox Maps SDK. -URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - -Mapbox Navigation uses portions of the The attribution module for the Mapbox Maps SDK. -URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - -Mapbox Navigation uses portions of the The camera animation module for the Mapbox Maps SDK for Android. -URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - -Mapbox Navigation uses portions of the The compass module for the Mapbox Maps SDK. -URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - -Mapbox Navigation uses portions of the The gestures module for the Mapbox Maps SDK for Android. -URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - -Mapbox Navigation uses portions of the The location component module for the Mapbox Maps SDK for Android. -URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - -Mapbox Navigation uses portions of the The logo module for the Mapbox Maps SDK for Android. -URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - -Mapbox Navigation uses portions of the The map lifecycle module for the Mapbox Maps SDK for Android. -URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - -Mapbox Navigation uses portions of the The map localization module for the Mapbox Maps SDK for Android. -URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - -Mapbox Navigation uses portions of the The map overlay module for the Mapbox Maps SDK for Android. -URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - -Mapbox Navigation uses portions of the The scalebar module for the Mapbox Maps SDK for Android. -URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - -Mapbox Navigation uses portions of the The style extension for the Mapbox Maps SDK for Android. -URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - -Mapbox Navigation uses portions of the The viewport module for the Mapbox Maps SDK. -URL: [https://github.com/mapbox/mapbox-maps-android](https://github.com/mapbox/mapbox-maps-android) -License: [BSD](https://opensource.org/licenses/BSD-2-Clause) - -=========================================================================== - Mapbox Navigation uses portions of the VersionedParcelable (Provides a stable but relatively compact binary serialization format that can be passed across processes or persisted safely.). URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== -Mapbox Navigation uses portions of the viewbinding. -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - #### Navigation UI App SDK module diff --git a/libnavui-androidauto/CHANGELOG.md b/libnavui-androidauto/CHANGELOG.md index 77e5ee6dd08..295f926fd32 100644 --- a/libnavui-androidauto/CHANGELOG.md +++ b/libnavui-androidauto/CHANGELOG.md @@ -5,6 +5,7 @@ Mapbox welcomes participation and contributions from everyone. ## Unreleased #### Features #### Bug fixes and improvements +- Use `MapboxAudioGuidance` from public api. [#6336](https://github.com/mapbox/mapbox-navigation-android/pull/6336) ## androidauto-v0.11.0 - Sep 16, 2022 ### Changelog diff --git a/libnavui-androidauto/api/current.txt b/libnavui-androidauto/api/current.txt index 993969ac966..fa947e6def3 100644 --- a/libnavui-androidauto/api/current.txt +++ b/libnavui-androidauto/api/current.txt @@ -17,10 +17,10 @@ package com.mapbox.androidauto { } public final class MapboxCarApp { - method public com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidance carAppAudioGuidanceService(); + method public com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance carAppAudioGuidanceService(); method public com.mapbox.androidauto.navigation.location.CarAppLocation carAppLocationService(); method public kotlinx.coroutines.flow.StateFlow getCarAppState(); - method public void setup(android.app.Application application); + method public void setup(); method public void updateCarAppState(com.mapbox.androidauto.CarAppState carAppState); property public final kotlinx.coroutines.flow.StateFlow carAppState; field public static final com.mapbox.androidauto.MapboxCarApp INSTANCE; diff --git a/libnavui-androidauto/build.gradle b/libnavui-androidauto/build.gradle index 86755f55876..fe186ae1872 100644 --- a/libnavui-androidauto/build.gradle +++ b/libnavui-androidauto/build.gradle @@ -45,10 +45,9 @@ dependencies { def carSearchVersion = "1.0.0-beta.36" api("com.mapbox.search:mapbox-search-android:${carSearchVersion}") - debugApi project(":libnavigation-android") - releaseApi("com.mapbox.navigation:android:${carNavVersion}") - debugImplementation project(":libnavui-app") - releaseImplementation("com.mapbox.navigation:ui-app:${carNavVersion}") + // TODO use the carNavVersion when 2.9.0-alpha.2 is available + api(project(":libnavigation-android")) +// api("com.mapbox.navigation:android:${carNavVersion}") implementation(dependenciesList.androidXAppCompat) implementation(dependenciesList.coroutinesCore) diff --git a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/MapboxCarApp.kt b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/MapboxCarApp.kt index 0b334086aef..fb7a4f79b5b 100644 --- a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/MapboxCarApp.kt +++ b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/MapboxCarApp.kt @@ -1,19 +1,16 @@ package com.mapbox.androidauto -import android.app.Application import com.mapbox.androidauto.navigation.location.CarAppLocation import com.mapbox.androidauto.navigation.location.impl.CarAppLocationImpl import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp -import com.mapbox.navigation.ui.app.internal.SharedApp -import com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidance +import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow /** * The entry point for your Mapbox Android Auto app. */ -@OptIn(ExperimentalPreviewMapboxNavigationAPI::class) object MapboxCarApp { private val carAppStateFlow = MutableStateFlow(FreeDriveState) @@ -43,12 +40,15 @@ object MapboxCarApp { } /** - * Setup android auto from your [Application.onCreate] - * - * @param application used to detect when activities are foregrounded + * Setup android auto with defaults */ - fun setup(application: Application) { - SharedApp.setup(application) - MapboxNavigationApp.registerObserver(CarAppLocationImpl()) + @OptIn(ExperimentalPreviewMapboxNavigationAPI::class) + fun setup() { + if (MapboxNavigationApp.getObservers(MapboxAudioGuidance::class).isEmpty()) { + MapboxNavigationApp.registerObserver(MapboxAudioGuidance()) + } + if (MapboxNavigationApp.getObservers(CarAppLocation::class).isEmpty()) { + MapboxNavigationApp.registerObserver(CarAppLocationImpl()) + } } } diff --git a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/AppAudioGuidanceUi.kt b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/AppAudioGuidanceUi.kt index 68d1b1c7524..4141c1de397 100644 --- a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/AppAudioGuidanceUi.kt +++ b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/AppAudioGuidanceUi.kt @@ -8,7 +8,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.mapbox.androidauto.MapboxCarApp -import com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidance +import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidanceState import com.mapbox.navigation.ui.voice.view.MapboxSoundButton import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch @@ -40,7 +40,7 @@ fun Fragment.attachAudioGuidance( */ fun Lifecycle.muteAudioGuidance() { addObserver(object : DefaultLifecycleObserver { - lateinit var initialState: MapboxAudioGuidance.State + lateinit var initialState: MapboxAudioGuidanceState override fun onResume(owner: LifecycleOwner) { with(MapboxCarApp.carAppAudioGuidanceService()) { initialState = stateFlow().value @@ -50,7 +50,7 @@ fun Lifecycle.muteAudioGuidance() { override fun onPause(owner: LifecycleOwner) { if (!initialState.isMuted) { - MapboxCarApp.carAppAudioGuidanceService().unmute() + MapboxCarApp.carAppAudioGuidanceService().unMute() } } }) diff --git a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/CarAudioGuidanceUi.kt b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/CarAudioGuidanceUi.kt index fd24bc5341b..e76207ea719 100644 --- a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/CarAudioGuidanceUi.kt +++ b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/CarAudioGuidanceUi.kt @@ -36,7 +36,7 @@ class CarAudioGuidanceUi : MapboxActionProvider.ScreenActionProvider { } } else { buildIconAction(screen, R.drawable.mapbox_car_ic_volume_off) { - audioGuidance.unmute() + audioGuidance.unMute() } } } diff --git a/libnavui-app/src/main/java/com/mapbox/navigation/ui/app/internal/SharedApp.kt b/libnavui-app/src/main/java/com/mapbox/navigation/ui/app/internal/SharedApp.kt index fd746397e96..bafe9bd059a 100644 --- a/libnavui-app/src/main/java/com/mapbox/navigation/ui/app/internal/SharedApp.kt +++ b/libnavui-app/src/main/java/com/mapbox/navigation/ui/app/internal/SharedApp.kt @@ -1,6 +1,5 @@ package com.mapbox.navigation.ui.app.internal -import android.content.Context import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI import com.mapbox.navigation.core.internal.extensions.attachCreated import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp @@ -17,9 +16,7 @@ import com.mapbox.navigation.ui.app.internal.controller.StateResetController import com.mapbox.navigation.ui.app.internal.controller.TripSessionStarterStateController import com.mapbox.navigation.ui.maps.internal.ui.RouteAlternativeComponent import com.mapbox.navigation.ui.maps.internal.ui.RouteAlternativeContract -import com.mapbox.navigation.ui.utils.internal.datastore.NavigationDataStoreOwner -import com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidance -import com.mapbox.navigation.ui.voice.internal.impl.MapboxAudioGuidanceImpl +import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance import java.util.concurrent.atomic.AtomicBoolean @OptIn(ExperimentalPreviewMapboxNavigationAPI::class) @@ -55,8 +52,6 @@ object SharedApp { @JvmOverloads fun setup( - context: Context, - audioGuidance: MapboxAudioGuidance? = null, routeAlternativeContract: RouteAlternativeContract? = null ) { if (isSetup) return @@ -69,7 +64,12 @@ object SharedApp { } ) MapboxNavigationApp.lifecycleOwner.attachCreated(*navigationObservers) - MapboxNavigationApp.registerObserver(audioGuidance ?: defaultAudioGuidance(context)) + + // TODO Remove this from SharedApp. The components that use `MapboxAudioGuidance` + // will "ensureAudioGuidanceRegistered". See the `ComponentInstaller.audioGuidanceButton` + if (MapboxNavigationApp.getObservers(MapboxAudioGuidance::class).isEmpty()) { + MapboxNavigationApp.registerObserver(MapboxAudioGuidance()) + } } fun tripSessionTransaction(updateSession: () -> Unit) { @@ -80,12 +80,4 @@ object SharedApp { updateSession() ignoreTripSessionUpdates.set(false) } - - private fun defaultAudioGuidance(context: Context): MapboxAudioGuidance { - return MapboxAudioGuidanceImpl.create(context).also { - it.dataStoreOwner = NavigationDataStoreOwner(context, DEFAULT_DATA_STORE_NAME) - } - } - - private const val DEFAULT_DATA_STORE_NAME = "mapbox_navigation_preferences" } diff --git a/libnavui-app/src/main/java/com/mapbox/navigation/ui/app/internal/controller/AudioGuidanceStateController.kt b/libnavui-app/src/main/java/com/mapbox/navigation/ui/app/internal/controller/AudioGuidanceStateController.kt index 4ae382ac442..26ce94a1e82 100644 --- a/libnavui-app/src/main/java/com/mapbox/navigation/ui/app/internal/controller/AudioGuidanceStateController.kt +++ b/libnavui-app/src/main/java/com/mapbox/navigation/ui/app/internal/controller/AudioGuidanceStateController.kt @@ -8,7 +8,7 @@ import com.mapbox.navigation.ui.app.internal.State import com.mapbox.navigation.ui.app.internal.Store import com.mapbox.navigation.ui.app.internal.audioguidance.AudioAction import com.mapbox.navigation.ui.app.internal.audioguidance.AudioGuidanceState -import com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidance +import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance /** * This class is responsible for playing voice instructions. Use the [AudioAction] to turning the @@ -59,7 +59,7 @@ class AudioGuidanceStateController( if (it.isMuted) { audioGuidance.mute() } else { - audioGuidance.unmute() + audioGuidance.unMute() } } } diff --git a/libnavui-app/src/test/java/com/mapbox/navigation/ui/app/internal/controller/AudioGuidanceStateControllerTest.kt b/libnavui-app/src/test/java/com/mapbox/navigation/ui/app/internal/controller/AudioGuidanceStateControllerTest.kt index bd5b22d07f3..72c845349a9 100644 --- a/libnavui-app/src/test/java/com/mapbox/navigation/ui/app/internal/controller/AudioGuidanceStateControllerTest.kt +++ b/libnavui-app/src/test/java/com/mapbox/navigation/ui/app/internal/controller/AudioGuidanceStateControllerTest.kt @@ -1,7 +1,5 @@ package com.mapbox.navigation.ui.app.internal.controller -import com.mapbox.api.directions.v5.models.VoiceInstructions -import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI import com.mapbox.navigation.core.MapboxNavigation import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp import com.mapbox.navigation.testing.MainCoroutineRule @@ -10,8 +8,8 @@ import com.mapbox.navigation.ui.app.internal.audioguidance.AudioAction import com.mapbox.navigation.ui.app.internal.audioguidance.AudioGuidanceState import com.mapbox.navigation.ui.app.internal.navigation.NavigationState import com.mapbox.navigation.ui.app.testing.TestStore -import com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidance -import com.mapbox.navigation.ui.voice.model.SpeechAnnouncement +import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance +import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidanceState import io.mockk.every import io.mockk.mockk import io.mockk.mockkObject @@ -27,13 +25,13 @@ import org.junit.Before import org.junit.Rule import org.junit.Test -@OptIn(ExperimentalPreviewMapboxNavigationAPI::class, ExperimentalCoroutinesApi::class) +@OptIn(ExperimentalCoroutinesApi::class) class AudioGuidanceStateControllerTest { @get:Rule var coroutineRule = MainCoroutineRule() - private lateinit var audioGuidanceState: MutableStateFlow + private lateinit var audioGuidanceState: MutableStateFlow private lateinit var mockAudioGuidance: MapboxAudioGuidance private lateinit var testStore: TestStore @@ -42,7 +40,7 @@ class AudioGuidanceStateControllerTest { mockkObject(MapboxNavigationApp) audioGuidanceState = MutableStateFlow( - TestAudioGuidanceState(isMuted = false) + mockk { every { isMuted } returns false } ) mockAudioGuidance = mockk(relaxed = true) { every { stateFlow() } returns audioGuidanceState @@ -68,7 +66,7 @@ class AudioGuidanceStateControllerTest { audio = AudioGuidanceState(isMuted = false) ) ) - audioGuidanceState.value = TestAudioGuidanceState(isMuted = true) + audioGuidanceState.value = mockk { every { isMuted } returns true } sut.onAttached(mockMapboxNavigation()) assertTrue(testStore.state.value.audio.isMuted) @@ -83,7 +81,7 @@ class AudioGuidanceStateControllerTest { audio = AudioGuidanceState(isMuted = false) ) ) - audioGuidanceState.value = TestAudioGuidanceState(isMuted = false) + audioGuidanceState.value = mockk { every { isMuted } returns false } sut.onAttached(mockMapboxNavigation()) testStore.setState( @@ -118,11 +116,4 @@ class AudioGuidanceStateControllerTest { every { MapboxNavigationApp.current() } returns mapboxNavigation return mapboxNavigation } - - private data class TestAudioGuidanceState( - override val isMuted: Boolean, - override val isPlayable: Boolean = false, - override val voiceInstructions: VoiceInstructions? = null, - override val speechAnnouncement: SpeechAnnouncement? = null - ) : MapboxAudioGuidance.State } diff --git a/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/NavigationView.kt b/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/NavigationView.kt index e8cef2606d5..d3fd69ac3fc 100644 --- a/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/NavigationView.kt +++ b/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/NavigationView.kt @@ -2,7 +2,6 @@ package com.mapbox.navigation.dropin import android.Manifest import android.app.Activity -import android.app.Application import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater @@ -109,7 +108,7 @@ class NavigationView @JvmOverloads constructor( keepScreenOn = true captureSystemBarsInsets() - SharedApp.setup(context.applicationContext as Application) + SharedApp.setup() if (!MapboxNavigationApp.isSetup()) { MapboxNavigationApp.setup( NavigationOptions.Builder(context) diff --git a/libnavui-voice/api/current.txt b/libnavui-voice/api/current.txt index c80864ba9a6..ce96ed7ece0 100644 --- a/libnavui-voice/api/current.txt +++ b/libnavui-voice/api/current.txt @@ -21,6 +21,27 @@ package com.mapbox.navigation.ui.voice.api { method public operator void invoke(boolean result); } + public final class MapboxAudioGuidance implements com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver { + ctor public MapboxAudioGuidance(); + method public void mute(); + method public void onAttached(com.mapbox.navigation.core.MapboxNavigation mapboxNavigation); + method public void onDetached(com.mapbox.navigation.core.MapboxNavigation mapboxNavigation); + method public kotlinx.coroutines.flow.StateFlow stateFlow(); + method public void toggle(); + method public void unMute(); + } + + public final class MapboxAudioGuidanceState { + method public com.mapbox.navigation.ui.voice.model.SpeechAnnouncement? getSpeechAnnouncement(); + method public com.mapbox.api.directions.v5.models.VoiceInstructions? getVoiceInstructions(); + method public boolean isMuted(); + method public boolean isPlayable(); + property public final boolean isMuted; + property public final boolean isPlayable; + property public final com.mapbox.navigation.ui.voice.model.SpeechAnnouncement? speechAnnouncement; + property public final com.mapbox.api.directions.v5.models.VoiceInstructions? voiceInstructions; + } + public final class MapboxSpeechApi { ctor public MapboxSpeechApi(android.content.Context context, String accessToken, String language, com.mapbox.navigation.ui.voice.options.MapboxSpeechApiOptions options = MapboxSpeechApiOptions.().build()); ctor public MapboxSpeechApi(android.content.Context context, String accessToken, String language); diff --git a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/impl/MapboxAudioGuidanceImpl.kt b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidance.kt similarity index 74% rename from libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/impl/MapboxAudioGuidanceImpl.kt rename to libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidance.kt index 50547a8fd17..cdf0285f57f 100644 --- a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/impl/MapboxAudioGuidanceImpl.kt +++ b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidance.kt @@ -1,16 +1,14 @@ -package com.mapbox.navigation.ui.voice.internal.impl +package com.mapbox.navigation.ui.voice.api -import android.content.Context -import com.mapbox.api.directions.v5.models.VoiceInstructions -import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI +import androidx.annotation.VisibleForTesting import com.mapbox.navigation.core.MapboxNavigation +import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp +import com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver import com.mapbox.navigation.ui.utils.internal.configuration.NavigationConfigOwner import com.mapbox.navigation.ui.utils.internal.datastore.NavigationDataStoreOwner import com.mapbox.navigation.ui.utils.internal.datastore.booleanDataStoreKey -import com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidance -import com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidanceServices import com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidanceVoice -import com.mapbox.navigation.ui.voice.model.SpeechAnnouncement +import com.mapbox.navigation.ui.voice.internal.impl.MapboxAudioGuidanceServices import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -35,15 +33,17 @@ import kotlinx.coroutines.launch /** * Implementation of [MapboxAudioGuidance]. See interface for details. */ -@ExperimentalPreviewMapboxNavigationAPI -class MapboxAudioGuidanceImpl( +class MapboxAudioGuidance +@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) +internal constructor( private val audioGuidanceServices: MapboxAudioGuidanceServices, - private val configOwner: NavigationConfigOwner, - dispatcher: CoroutineDispatcher = Dispatchers.Main, -) : MapboxAudioGuidance { + dispatcher: CoroutineDispatcher, +) : MapboxNavigationObserver { - var dataStoreOwner: NavigationDataStoreOwner? = null + constructor() : this(MapboxAudioGuidanceServices(), Dispatchers.Main) + private var dataStoreOwner: NavigationDataStoreOwner? = null + private var configOwner: NavigationConfigOwner? = null private var mutedStateFlow = MutableStateFlow(false) private val internalStateFlow = MutableStateFlow(MapboxAudioGuidanceState()) private val scope = CoroutineScope(SupervisorJob() + dispatcher) @@ -51,7 +51,13 @@ class MapboxAudioGuidanceImpl( private var job: Job? = null + /** + * @see [MapboxNavigationApp] + */ override fun onAttached(mapboxNavigation: MapboxNavigation) { + val context = mapboxNavigation.navigationOptions.applicationContext + dataStoreOwner = audioGuidanceServices.dataStoreOwner(context, DEFAULT_DATA_STORE_NAME) + configOwner = audioGuidanceServices.configOwner(context) mapboxVoiceInstructions.registerObservers(mapboxNavigation) job = scope.launch { restoreMutedState() @@ -59,6 +65,9 @@ class MapboxAudioGuidanceImpl( } } + /** + * @see [MapboxNavigationApp] + */ override fun onDetached(mapboxNavigation: MapboxNavigation) { mapboxVoiceInstructions.unregisterObservers(mapboxNavigation) job?.cancel() @@ -71,14 +80,14 @@ class MapboxAudioGuidanceImpl( * In order to enable voice guidance, you must call [MapboxNavigation.startTripSession] * and set a route for active guidance through [MapboxNavigation.setRoutes]. * - * You can also control audio guidance by calling [mute], [unmute] or [toggle] + * You can also control audio guidance by calling [mute], [unMute] or [toggle] */ - override fun stateFlow(): StateFlow = internalStateFlow + fun stateFlow(): StateFlow = internalStateFlow /** * Explicit call to mute the audio guidance state. */ - override fun mute() { + fun mute() { scope.launch { setMutedState(true) } @@ -87,7 +96,7 @@ class MapboxAudioGuidanceImpl( /** * Explicit call to unmute the audio guidance state. */ - override fun unmute() { + fun unMute() { scope.launch { setMutedState(false) } @@ -96,10 +105,10 @@ class MapboxAudioGuidanceImpl( /** * Toggle the muted state. E.g., if audio is muted, make it unmuted. */ - override fun toggle() { + fun toggle() { scope.launch { if (mutedStateFlow.value) { - unmute() + unMute() } else { mute() } @@ -112,10 +121,10 @@ class MapboxAudioGuidanceImpl( @OptIn(ExperimentalCoroutinesApi::class) private fun audioGuidanceFlow( mapboxNavigation: MapboxNavigation - ): Flow { + ): Flow { return combine( mapboxVoiceInstructions.voiceLanguage(), - configOwner.language(), + configOwner!!.language(), ) { voiceLanguage, deviceLanguage -> voiceLanguage ?: deviceLanguage } .distinctUntilChanged() .flatMapLatest { language -> @@ -134,7 +143,7 @@ class MapboxAudioGuidanceImpl( /** * This flow will monitor navigation state to determine if audio is available. */ - private fun silentFlow(): Flow { + private fun silentFlow(): Flow { return mapboxVoiceInstructions.voiceInstructions() .map { state -> internalStateFlow.updateAndGet { @@ -153,7 +162,7 @@ class MapboxAudioGuidanceImpl( @OptIn(FlowPreview::class) private fun speechFlow( audioGuidance: MapboxAudioGuidanceVoice - ): Flow { + ): Flow { return mapboxVoiceInstructions.voiceInstructions() .flatMapConcat { voice -> internalStateFlow.update { @@ -166,7 +175,14 @@ class MapboxAudioGuidanceImpl( audioGuidance.speak(voice.voiceInstructions) } .map { speechAnnouncement -> - internalStateFlow.updateAndGet { it.copy(speechAnnouncement = speechAnnouncement) } + internalStateFlow.updateAndGet { + MapboxAudioGuidanceState( + isPlayable = it.isPlayable, + isMuted = it.isMuted, + voiceInstructions = it.voiceInstructions, + speechAnnouncement = speechAnnouncement + ) + } } } @@ -181,22 +197,9 @@ class MapboxAudioGuidanceImpl( dataStoreOwner?.write(STORE_AUDIO_GUIDANCE_MUTED, muted) } - companion object { - val STORE_AUDIO_GUIDANCE_MUTED = + private companion object { + private val STORE_AUDIO_GUIDANCE_MUTED = booleanDataStoreKey("audio_guidance_muted", false) - - fun create(context: Context): MapboxAudioGuidanceImpl { - return MapboxAudioGuidanceImpl( - MapboxAudioGuidanceServicesImpl(), - NavigationConfigOwner(context) - ) - } + private const val DEFAULT_DATA_STORE_NAME = "mapbox_navigation_preferences" } } - -private data class MapboxAudioGuidanceState( - override val isPlayable: Boolean = false, - override val isMuted: Boolean = false, - override val voiceInstructions: VoiceInstructions? = null, - override val speechAnnouncement: SpeechAnnouncement? = null, -) : MapboxAudioGuidance.State diff --git a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidanceState.kt b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidanceState.kt new file mode 100644 index 00000000000..2630d235230 --- /dev/null +++ b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidanceState.kt @@ -0,0 +1,74 @@ +package com.mapbox.navigation.ui.voice.api + +import com.mapbox.api.directions.v5.models.VoiceInstructions +import com.mapbox.navigation.ui.voice.model.SpeechAnnouncement + +/** + * Represents the state of [MapboxAudioGuidance]. + */ +class MapboxAudioGuidanceState internal constructor( + /** + * When the trip session has started, and there is an active route. + */ + val isPlayable: Boolean = false, + + /** + * Controlled by the [MapboxAudioGuidance] service. When [MapboxAudioGuidance.mute] is called + * this will be changed to true. + */ + val isMuted: Boolean = false, + + /** + * Once a voice instruction becomes available this will not be null. + * When the state [isPlayable] and this is null, it means there are no voice instructions + * on the route at this time. + */ + val voiceInstructions: VoiceInstructions? = null, + + /** + * After a [voiceInstructions] has been announced, this value will be emitted. + * This will always be null when [isMuted] is true. + */ + val speechAnnouncement: SpeechAnnouncement? = null, +) { + + /** + * Regenerate whenever a change is made + */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as MapboxAudioGuidanceState + + if (isPlayable != other.isPlayable) return false + if (isMuted != other.isMuted) return false + if (voiceInstructions != other.voiceInstructions) return false + if (speechAnnouncement != other.speechAnnouncement) return false + + return true + } + + /** + * Regenerate whenever a change is made + */ + override fun hashCode(): Int { + var result = isPlayable.hashCode() + result = 31 * result + isMuted.hashCode() + result = 31 * result + (voiceInstructions?.hashCode() ?: 0) + result = 31 * result + (speechAnnouncement?.hashCode() ?: 0) + return result + } + + /** + * Regenerate whenever a change is made + */ + override fun toString(): String { + return "MapboxAudioGuidanceState(" + + "isPlayable=$isPlayable, " + + "isMuted=$isMuted, " + + "voiceInstructions=$voiceInstructions, " + + "speechAnnouncement=$speechAnnouncement" + + ")" + } +} diff --git a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/installer/ComponentInstaller.kt b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/installer/ComponentInstaller.kt index 60d46192905..f441ef86928 100644 --- a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/installer/ComponentInstaller.kt +++ b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/installer/ComponentInstaller.kt @@ -1,12 +1,10 @@ package com.mapbox.navigation.ui.voice.installer -import android.content.Context import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp import com.mapbox.navigation.ui.base.installer.ComponentInstaller import com.mapbox.navigation.ui.base.installer.Installation -import com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidance -import com.mapbox.navigation.ui.voice.internal.impl.MapboxAudioGuidanceImpl +import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance import com.mapbox.navigation.ui.voice.internal.ui.AudioGuidanceButtonComponent import com.mapbox.navigation.ui.voice.view.MapboxAudioGuidanceButton @@ -19,14 +17,13 @@ import com.mapbox.navigation.ui.voice.view.MapboxAudioGuidanceButton */ @ExperimentalPreviewMapboxNavigationAPI fun ComponentInstaller.audioGuidanceButton(button: MapboxAudioGuidanceButton): Installation { - ensureAudioGuidanceRegistered(button.context) + ensureAudioGuidanceRegistered() return component(AudioGuidanceButtonComponent(button)) } @ExperimentalPreviewMapboxNavigationAPI -private fun ensureAudioGuidanceRegistered(context: Context) { +private fun ensureAudioGuidanceRegistered() { if (MapboxNavigationApp.getObservers(MapboxAudioGuidance::class).isEmpty()) { - val audioGuidance = MapboxAudioGuidanceImpl.create(context) - MapboxNavigationApp.registerObserver(audioGuidance) + MapboxNavigationApp.registerObserver(MapboxAudioGuidance()) } } diff --git a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/MapboxAudioGuidance.kt b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/MapboxAudioGuidance.kt deleted file mode 100644 index b76d65b3c43..00000000000 --- a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/MapboxAudioGuidance.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.mapbox.navigation.ui.voice.internal - -import com.mapbox.api.directions.v5.models.VoiceInstructions -import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI -import com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver -import com.mapbox.navigation.ui.voice.model.SpeechAnnouncement -import kotlinx.coroutines.flow.StateFlow - -/** - * Service interface accessible through [MapboxCarApp.carAppServices] - * - * It will start monitoring audio guidance once the class is referenced because it is lazy loaded. - * Use the controllable functions [mute], [unmute], [toggle] to change the voice guidance. The - * selection is saved to shared preferences and will become the default setting. - * - * Subscribing onto the [stateFlow] does not change the internal state. - */ -@OptIn(ExperimentalPreviewMapboxNavigationAPI::class) -interface MapboxAudioGuidance : MapboxNavigationObserver { - /** - * Monitor the voice instructions state. - */ - fun stateFlow(): StateFlow - - /** - * Continue to monitor voice instructions, but stop the audio voice. - */ - fun mute() - - /** - * Turn on the audio voice. - */ - fun unmute() - - /** - * Toggle the state between [mute] and [unmute]. - */ - fun toggle() - - /** - * Accessed through [stateFlow]. - */ - interface State { - /** - * When the trip session has started, and there is an active route. - */ - val isPlayable: Boolean - - /** - * Unrelated to the navigation state, provides state of - * the controls [mute] [unmute] [toggle] - */ - val isMuted: Boolean - - /** - * Once a voice instruction becomes available this will not be null. - * When the state [isPlayable] and this is null, it means there are no voice instructions - * on the route at this time. - */ - val voiceInstructions: VoiceInstructions? - - /** - * After a [voiceInstructions] has been announced, this value will be emitted. - * This will always be null when [isMuted] is true. - */ - val speechAnnouncement: SpeechAnnouncement? - } -} diff --git a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/MapboxAudioGuidanceServices.kt b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/MapboxAudioGuidanceServices.kt deleted file mode 100644 index 98b3262d670..00000000000 --- a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/MapboxAudioGuidanceServices.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.mapbox.navigation.ui.voice.internal - -import com.mapbox.navigation.core.MapboxNavigation -import com.mapbox.navigation.ui.voice.api.MapboxSpeechApi -import com.mapbox.navigation.ui.voice.api.MapboxVoiceInstructionsPlayer - -interface MapboxAudioGuidanceServices { - fun mapboxAudioGuidanceVoice( - mapboxNavigation: MapboxNavigation, - language: String - ): MapboxAudioGuidanceVoice - - fun mapboxSpeechApi(mapboxNavigation: MapboxNavigation, language: String): MapboxSpeechApi - fun mapboxVoiceInstructionsPlayer( - mapboxNavigation: MapboxNavigation, - language: String, - ): MapboxVoiceInstructionsPlayer - - fun mapboxVoiceInstructions(): MapboxVoiceInstructions -} diff --git a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/impl/MapboxAudioGuidanceServicesImpl.kt b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/impl/MapboxAudioGuidanceServices.kt similarity index 71% rename from libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/impl/MapboxAudioGuidanceServicesImpl.kt rename to libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/impl/MapboxAudioGuidanceServices.kt index 0442fe482ef..764820d3776 100644 --- a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/impl/MapboxAudioGuidanceServicesImpl.kt +++ b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/impl/MapboxAudioGuidanceServices.kt @@ -1,15 +1,17 @@ package com.mapbox.navigation.ui.voice.internal.impl +import android.content.Context import com.mapbox.navigation.core.MapboxNavigation +import com.mapbox.navigation.ui.utils.internal.configuration.NavigationConfigOwner +import com.mapbox.navigation.ui.utils.internal.datastore.NavigationDataStoreOwner import com.mapbox.navigation.ui.voice.api.MapboxSpeechApi import com.mapbox.navigation.ui.voice.api.MapboxVoiceInstructionsPlayer -import com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidanceServices import com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidanceVoice import com.mapbox.navigation.ui.voice.internal.MapboxVoiceInstructions -class MapboxAudioGuidanceServicesImpl : MapboxAudioGuidanceServices { +class MapboxAudioGuidanceServices { - override fun mapboxAudioGuidanceVoice( + fun mapboxAudioGuidanceVoice( mapboxNavigation: MapboxNavigation, language: String, ): MapboxAudioGuidanceVoice { @@ -22,7 +24,7 @@ class MapboxAudioGuidanceServicesImpl : MapboxAudioGuidanceServices { ) } - override fun mapboxSpeechApi( + fun mapboxSpeechApi( mapboxNavigation: MapboxNavigation, language: String ): MapboxSpeechApi { @@ -31,7 +33,7 @@ class MapboxAudioGuidanceServicesImpl : MapboxAudioGuidanceServices { return MapboxSpeechApi(applicationContext, accessToken, language) } - override fun mapboxVoiceInstructionsPlayer( + fun mapboxVoiceInstructionsPlayer( mapboxNavigation: MapboxNavigation, language: String, ): MapboxVoiceInstructionsPlayer { @@ -40,5 +42,10 @@ class MapboxAudioGuidanceServicesImpl : MapboxAudioGuidanceServices { return MapboxVoiceInstructionsPlayer(applicationContext, accessToken, language) } - override fun mapboxVoiceInstructions() = MapboxVoiceInstructions() + fun mapboxVoiceInstructions() = MapboxVoiceInstructions() + + fun configOwner(context: Context): NavigationConfigOwner = NavigationConfigOwner(context) + + fun dataStoreOwner(context: Context, storeName: String) = + NavigationDataStoreOwner(context, storeName) } diff --git a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponent.kt b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponent.kt index 90de9e82b54..ac36d57f04f 100644 --- a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponent.kt +++ b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponent.kt @@ -7,7 +7,7 @@ import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp import com.mapbox.navigation.ui.base.lifecycle.UIComponent import com.mapbox.navigation.ui.utils.internal.Provider import com.mapbox.navigation.ui.utils.internal.extensions.slice -import com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidance +import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance import com.mapbox.navigation.ui.voice.view.MapboxAudioGuidanceButton import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow @@ -39,7 +39,7 @@ internal class MapboxAudioComponentContract( } override fun unMute() { - audioGuidance.unmute() + audioGuidance.unMute() } } diff --git a/libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/TestMapboxAudioGuidanceServices.kt b/libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/TestMapboxAudioGuidanceServices.kt index c6a42c2a855..ab17cedc8b8 100644 --- a/libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/TestMapboxAudioGuidanceServices.kt +++ b/libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/TestMapboxAudioGuidanceServices.kt @@ -1,10 +1,11 @@ package com.mapbox.navigation.ui.voice import com.mapbox.api.directions.v5.models.VoiceInstructions -import com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidanceServices +import com.mapbox.navigation.ui.utils.internal.configuration.NavigationConfigOwner import com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidanceVoice import com.mapbox.navigation.ui.voice.internal.MapboxVoiceInstructions import com.mapbox.navigation.ui.voice.internal.MapboxVoiceInstructionsState +import com.mapbox.navigation.ui.voice.internal.impl.MapboxAudioGuidanceServices import com.mapbox.navigation.ui.voice.model.SpeechAnnouncement import io.mockk.Runs import io.mockk.every @@ -15,7 +16,9 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.onEach -class TestMapboxAudioGuidanceServices { +class TestMapboxAudioGuidanceServices( + private val deviceLanguage: String = "en" +) { private val voiceInstructionsFlow = MutableStateFlow( MapboxVoiceInstructionsState() @@ -48,9 +51,19 @@ class TestMapboxAudioGuidanceServices { } } + private val testCarAppDataStoreOwner = TestCarAppDataStoreOwner() + + private val carAppConfigOwner: NavigationConfigOwner = mockk { + every { language() } returns flowOf(deviceLanguage) + } + + val dataStoreOwner = testCarAppDataStoreOwner.carAppDataStoreOwner + val mapboxAudioGuidanceServices = mockk { every { mapboxVoiceInstructions() } returns mapboxVoiceInstructions every { mapboxAudioGuidanceVoice(any(), any()) } returns mapboxAudioGuidanceVoice + every { configOwner(any()) } returns carAppConfigOwner + every { dataStoreOwner(any(), any()) } returns dataStoreOwner } fun emitVoiceInstruction(state: MapboxVoiceInstructions.State) { diff --git a/libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/internal/impl/MapboxAudioGuidanceImplTest.kt b/libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidanceTest.kt similarity index 79% rename from libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/internal/impl/MapboxAudioGuidanceImplTest.kt rename to libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidanceTest.kt index a879ecf1ac5..dcad7f2483b 100644 --- a/libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/internal/impl/MapboxAudioGuidanceImplTest.kt +++ b/libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidanceTest.kt @@ -1,12 +1,10 @@ -package com.mapbox.navigation.ui.voice.internal.impl +package com.mapbox.navigation.ui.voice.api import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI +import com.mapbox.navigation.core.MapboxNavigation import com.mapbox.navigation.testing.MainCoroutineRule -import com.mapbox.navigation.ui.utils.internal.configuration.NavigationConfigOwner -import com.mapbox.navigation.ui.voice.TestCarAppDataStoreOwner import com.mapbox.navigation.ui.voice.TestMapboxAudioGuidanceServices import com.mapbox.navigation.ui.voice.TestMapboxAudioGuidanceServices.Companion.SPEECH_ANNOUNCEMENT_DELAY_MS -import com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidance import com.mapbox.navigation.ui.voice.internal.MapboxVoiceInstructions import io.mockk.every import io.mockk.excludeRecords @@ -17,7 +15,6 @@ import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.launch import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse @@ -26,50 +23,46 @@ import org.junit.Assert.assertTrue import org.junit.Rule import org.junit.Test -private const val deviceLanguage = "en" - @ExperimentalCoroutinesApi @ExperimentalPreviewMapboxNavigationAPI -class MapboxAudioGuidanceImplTest { +class MapboxAudioGuidanceTest { @get:Rule val coroutineRule = MainCoroutineRule() private val testMapboxAudioGuidanceServices = TestMapboxAudioGuidanceServices() - private val testCarAppDataStoreOwner = TestCarAppDataStoreOwner() - private val carAppConfigOwner: NavigationConfigOwner = mockk { - every { language() } returns flowOf(deviceLanguage) + private val mapboxNavigation: MapboxNavigation = mockk { + every { navigationOptions } returns mockk { + every { applicationContext } returns mockk() + } } - private val carAppAudioGuidance = MapboxAudioGuidanceImpl( + private val carAppAudioGuidance = MapboxAudioGuidance( testMapboxAudioGuidanceServices.mapboxAudioGuidanceServices, - carAppConfigOwner, coroutineRule.testDispatcher, - ).apply { - dataStoreOwner = testCarAppDataStoreOwner.carAppDataStoreOwner - } + ) @Test fun `empty state flow by default`() = coroutineRule.runBlockingTest { - carAppAudioGuidance.onAttached(mockk()) + carAppAudioGuidance.onAttached(mapboxNavigation) val initialState = carAppAudioGuidance.stateFlow().first() assertEquals(false, initialState.isPlayable) assertEquals(false, initialState.isMuted) assertNull(initialState.speechAnnouncement) - carAppAudioGuidance.onDetached(mockk()) + carAppAudioGuidance.onDetached(mapboxNavigation) } @Test fun `completes full lifecycle`() = coroutineRule.runBlockingTest { - val states = mutableListOf() + val states = mutableListOf() val job = launch { carAppAudioGuidance.stateFlow().collect { states.add(it) } } - carAppAudioGuidance.onAttached(mockk()) - carAppAudioGuidance.onDetached(mockk()) + carAppAudioGuidance.onAttached(mapboxNavigation) + carAppAudioGuidance.onDetached(mapboxNavigation) assertEquals(1, states.size) job.cancelAndJoin() @@ -77,8 +70,8 @@ class MapboxAudioGuidanceImplTest { @Test fun `becomes playable before voice instructions arrive`() = coroutineRule.runBlockingTest { - carAppAudioGuidance.onAttached(mockk()) - val states = mutableListOf() + carAppAudioGuidance.onAttached(mapboxNavigation) + val states = mutableListOf() val job = launch { carAppAudioGuidance.stateFlow().collect { states.add(it) } } @@ -94,13 +87,13 @@ class MapboxAudioGuidanceImplTest { assertTrue(states[1].isPlayable) assertNull(states[1].speechAnnouncement) job.cancelAndJoin() - carAppAudioGuidance.onDetached(mockk()) + carAppAudioGuidance.onDetached(mapboxNavigation) } @Test fun `plays voice instructions`() = coroutineRule.runBlockingTest { - carAppAudioGuidance.onAttached(mockk()) - val states = mutableListOf() + carAppAudioGuidance.onAttached(mapboxNavigation) + val states = mutableListOf() val job = launch { carAppAudioGuidance.stateFlow().collect { states.add(it) } } @@ -122,13 +115,13 @@ class MapboxAudioGuidanceImplTest { states[2].speechAnnouncement?.announcement ) job.cancelAndJoin() - carAppAudioGuidance.onDetached(mockk()) + carAppAudioGuidance.onDetached(mapboxNavigation) } @Test fun `does not play when muted but provides announcement`() = coroutineRule.runBlockingTest { - carAppAudioGuidance.onAttached(mockk()) - val states = mutableListOf() + carAppAudioGuidance.onAttached(mapboxNavigation) + val states = mutableListOf() val job = launch { carAppAudioGuidance.stateFlow().collect { states.add(it) } } @@ -152,13 +145,13 @@ class MapboxAudioGuidanceImplTest { ) assertNull(states[2].speechAnnouncement) job.cancelAndJoin() - carAppAudioGuidance.onDetached(mockk()) + carAppAudioGuidance.onDetached(mapboxNavigation) } @Test fun `plays voice instructions without canceling previous`() = coroutineRule.runBlockingTest { - carAppAudioGuidance.onAttached(mockk()) - val states = mutableListOf>() + carAppAudioGuidance.onAttached(mapboxNavigation) + val states = mutableListOf>() val job = launch { carAppAudioGuidance.stateFlow().collect { states.add(it to currentTime) @@ -193,13 +186,13 @@ class MapboxAudioGuidanceImplTest { assertEquals("You have arrived at your destination", secondAnnouncement) assertEquals(SPEECH_ANNOUNCEMENT_DELAY_MS * 2, states[4].second) job.cancelAndJoin() - carAppAudioGuidance.onDetached(mockk()) + carAppAudioGuidance.onDetached(mapboxNavigation) } @Test fun `voice language from route is preferred to device language`() = coroutineRule.runBlockingTest { - carAppAudioGuidance.onAttached(mockk()) + carAppAudioGuidance.onAttached(mapboxNavigation) val voiceLanguage = "ru" testMapboxAudioGuidanceServices.emitVoiceLanguage(voiceLanguage) @@ -211,9 +204,11 @@ class MapboxAudioGuidanceImplTest { mapboxAudioGuidanceServices.mapboxVoiceInstructions() } verifySequence { - mapboxAudioGuidanceServices.mapboxAudioGuidanceVoice(any(), deviceLanguage) + mapboxAudioGuidanceServices.dataStoreOwner(any(), any()) + mapboxAudioGuidanceServices.configOwner(any()) + mapboxAudioGuidanceServices.mapboxAudioGuidanceVoice(any(), "en") mapboxAudioGuidanceServices.mapboxAudioGuidanceVoice(any(), voiceLanguage) } - carAppAudioGuidance.onDetached(mockk()) + carAppAudioGuidance.onDetached(mapboxNavigation) } } diff --git a/libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponentTest.kt b/libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponentTest.kt index b0a11bc16e1..f66353c691f 100644 --- a/libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponentTest.kt +++ b/libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponentTest.kt @@ -3,13 +3,12 @@ package com.mapbox.navigation.ui.voice.internal.ui import android.content.Context import androidx.core.view.isVisible import androidx.test.core.app.ApplicationProvider -import com.mapbox.api.directions.v5.models.VoiceInstructions import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI import com.mapbox.navigation.core.MapboxNavigation import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp import com.mapbox.navigation.testing.MainCoroutineRule -import com.mapbox.navigation.ui.voice.internal.MapboxAudioGuidance -import com.mapbox.navigation.ui.voice.model.SpeechAnnouncement +import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance +import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidanceState import com.mapbox.navigation.ui.voice.view.MapboxAudioGuidanceButton import io.mockk.every import io.mockk.mockk @@ -103,13 +102,13 @@ class AudioGuidanceButtonComponentTest { @Test fun `onAttach - default contract`() { - val testState = MutableStateFlow( - TestMapboxAudioGuidanceState(isMuted = false) + val testState = MutableStateFlow( + MapboxAudioGuidanceState(isMuted = false) ) val mockAudioGuidance = mockk { every { stateFlow() } returns testState every { mute() } returns Unit - every { unmute() } returns Unit + every { unMute() } returns Unit every { toggle() } returns Unit } every { @@ -146,11 +145,4 @@ class AudioGuidanceButtonComponentTest { isMuted.value = false } } - - private data class TestMapboxAudioGuidanceState( - override val isPlayable: Boolean = false, - override val isMuted: Boolean = false, - override val voiceInstructions: VoiceInstructions? = null, - override val speechAnnouncement: SpeechAnnouncement? = null, - ) : MapboxAudioGuidance.State } diff --git a/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/QaTestApplication.kt b/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/QaTestApplication.kt index 58d2652edb7..fa5501d96ef 100644 --- a/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/QaTestApplication.kt +++ b/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/QaTestApplication.kt @@ -1,13 +1,5 @@ package com.mapbox.navigation.qa_test_app import android.app.Application -import com.mapbox.androidauto.MapboxCarApp -class QaTestApplication : Application() { - - override fun onCreate() { - super.onCreate() - - MapboxCarApp.setup(this) - } -} +class QaTestApplication : Application() diff --git a/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/car/MainCarSession.kt b/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/car/MainCarSession.kt index ee6970fa8c1..e26b6323f33 100644 --- a/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/car/MainCarSession.kt +++ b/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/car/MainCarSession.kt @@ -13,6 +13,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.mapbox.android.core.permissions.PermissionsManager +import com.mapbox.androidauto.MapboxCarApp import com.mapbox.androidauto.MapboxCarNavigationManager import com.mapbox.androidauto.car.MainCarContext import com.mapbox.androidauto.car.MainScreenManager @@ -47,6 +48,7 @@ class MainCarSession : Session() { init { logAndroidAuto("MainCarSession constructor") + MapboxCarApp.setup() val logoSurfaceRenderer = CarLogoSurfaceRenderer() val compassSurfaceRenderer = CarCompassSurfaceRenderer() MapboxNavigationApp.attach(lifecycleOwner = this) From 9d8a6cfe80e3bfb52eed71f5ee5101669e4b5710 Mon Sep 17 00:00:00 2001 From: Kyle Madsen Date: Fri, 16 Sep 2022 13:42:52 -0700 Subject: [PATCH 2/6] Move audio guidance out of shared app --- .../navigation/ui/app/internal/SharedApp.kt | 7 ------ .../ui/AudioGuidanceButtonComponent.kt | 4 +++- .../ui/AudioGuidanceButtonComponentTest.kt | 23 +++++++++++++++++-- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/libnavui-app/src/main/java/com/mapbox/navigation/ui/app/internal/SharedApp.kt b/libnavui-app/src/main/java/com/mapbox/navigation/ui/app/internal/SharedApp.kt index bafe9bd059a..50ea0a2365d 100644 --- a/libnavui-app/src/main/java/com/mapbox/navigation/ui/app/internal/SharedApp.kt +++ b/libnavui-app/src/main/java/com/mapbox/navigation/ui/app/internal/SharedApp.kt @@ -16,7 +16,6 @@ import com.mapbox.navigation.ui.app.internal.controller.StateResetController import com.mapbox.navigation.ui.app.internal.controller.TripSessionStarterStateController import com.mapbox.navigation.ui.maps.internal.ui.RouteAlternativeComponent import com.mapbox.navigation.ui.maps.internal.ui.RouteAlternativeContract -import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance import java.util.concurrent.atomic.AtomicBoolean @OptIn(ExperimentalPreviewMapboxNavigationAPI::class) @@ -64,12 +63,6 @@ object SharedApp { } ) MapboxNavigationApp.lifecycleOwner.attachCreated(*navigationObservers) - - // TODO Remove this from SharedApp. The components that use `MapboxAudioGuidance` - // will "ensureAudioGuidanceRegistered". See the `ComponentInstaller.audioGuidanceButton` - if (MapboxNavigationApp.getObservers(MapboxAudioGuidance::class).isEmpty()) { - MapboxNavigationApp.registerObserver(MapboxAudioGuidance()) - } } fun tripSessionTransaction(updateSession: () -> Unit) { diff --git a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponent.kt b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponent.kt index ac36d57f04f..28344855345 100644 --- a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponent.kt +++ b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponent.kt @@ -53,7 +53,9 @@ class AudioGuidanceButtonComponent( init { this.contractProvider = contractProvider ?: Provider { - val audioGuidance = MapboxNavigationApp.getObserver(MapboxAudioGuidance::class) + val audioGuidance = MapboxNavigationApp + .getObservers(MapboxAudioGuidance::class).firstOrNull() + ?: MapboxAudioGuidance().also { MapboxNavigationApp.registerObserver(it) } MapboxAudioComponentContract(coroutineScope, audioGuidance) } } diff --git a/libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponentTest.kt b/libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponentTest.kt index f66353c691f..c49a06b793b 100644 --- a/libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponentTest.kt +++ b/libnavui-voice/src/test/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponentTest.kt @@ -13,6 +13,7 @@ import com.mapbox.navigation.ui.voice.view.MapboxAudioGuidanceButton import io.mockk.every import io.mockk.mockk import io.mockk.mockkObject +import io.mockk.slot import io.mockk.spyk import io.mockk.unmockkAll import io.mockk.verify @@ -21,6 +22,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import org.junit.After import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule import org.junit.Test @@ -112,8 +114,8 @@ class AudioGuidanceButtonComponentTest { every { toggle() } returns Unit } every { - MapboxNavigationApp.getObserver(MapboxAudioGuidance::class) - } returns mockAudioGuidance + MapboxNavigationApp.getObservers(MapboxAudioGuidance::class) + } returns listOf(mockAudioGuidance) val sut = AudioGuidanceButtonComponent(button) sut.onAttached(mapboxNavigation) @@ -122,6 +124,23 @@ class AudioGuidanceButtonComponentTest { verify { mockAudioGuidance.mute() } } + @Test + fun `onAttach - create MapboxAudioGuidance if none exists`() { + val slotAudioGuidance = slot() + every { + MapboxNavigationApp.getObservers(MapboxAudioGuidance::class) + } returns emptyList() + every { + MapboxNavigationApp.registerObserver(capture(slotAudioGuidance)) + } returns MapboxNavigationApp + + val sut = AudioGuidanceButtonComponent(button) + sut.onAttached(mapboxNavigation) + button.performClick() + + assertTrue(slotAudioGuidance.isCaptured) + } + @Test fun `onDetached - should not handle button on click events`() { sut.onAttached(mapboxNavigation) From 12f0b73326f0278b9c0b2d34093ba86c43eda759 Mon Sep 17 00:00:00 2001 From: Kyle Madsen Date: Fri, 16 Sep 2022 18:02:47 -0700 Subject: [PATCH 3/6] Move constrcutor to private --- .../src/main/java/com/mapbox/androidauto/MapboxCarApp.kt | 9 --------- .../navigation/audioguidance/AppAudioGuidanceUi.kt | 9 +++++---- .../navigation/audioguidance/CarAudioGuidanceUi.kt | 5 +++-- .../navigation/ui/voice/api/MapboxAudioGuidance.kt | 9 ++++++--- .../navigation/ui/voice/installer/ComponentInstaller.kt | 9 --------- .../ui/voice/internal/ui/AudioGuidanceButtonComponent.kt | 6 +----- 6 files changed, 15 insertions(+), 32 deletions(-) diff --git a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/MapboxCarApp.kt b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/MapboxCarApp.kt index fb7a4f79b5b..6cc45fcfa61 100644 --- a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/MapboxCarApp.kt +++ b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/MapboxCarApp.kt @@ -26,12 +26,6 @@ object MapboxCarApp { fun carAppLocationService(): CarAppLocation = MapboxNavigationApp.getObserver(CarAppLocation::class) - /** - * Audio guidance service available to the car and app. - */ - fun carAppAudioGuidanceService(): MapboxAudioGuidance = - MapboxNavigationApp.getObserver(MapboxAudioGuidance::class) - /** * Keep your car and app in sync with CarAppState. */ @@ -44,9 +38,6 @@ object MapboxCarApp { */ @OptIn(ExperimentalPreviewMapboxNavigationAPI::class) fun setup() { - if (MapboxNavigationApp.getObservers(MapboxAudioGuidance::class).isEmpty()) { - MapboxNavigationApp.registerObserver(MapboxAudioGuidance()) - } if (MapboxNavigationApp.getObservers(CarAppLocation::class).isEmpty()) { MapboxNavigationApp.registerObserver(CarAppLocationImpl()) } diff --git a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/AppAudioGuidanceUi.kt b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/AppAudioGuidanceUi.kt index 4141c1de397..64c70091aef 100644 --- a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/AppAudioGuidanceUi.kt +++ b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/AppAudioGuidanceUi.kt @@ -8,6 +8,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.mapbox.androidauto.MapboxCarApp +import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidanceState import com.mapbox.navigation.ui.voice.view.MapboxSoundButton import kotlinx.coroutines.flow.collect @@ -17,7 +18,7 @@ fun Fragment.attachAudioGuidance( mapboxSoundButton: MapboxSoundButton ) { val lifecycleOwner = viewLifecycleOwner - val flow = MapboxCarApp.carAppAudioGuidanceService().stateFlow() + val flow = MapboxAudioGuidance.getInstance().stateFlow() lifecycleOwner.lifecycleScope.launch { lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { flow.collect { state -> @@ -31,7 +32,7 @@ fun Fragment.attachAudioGuidance( } } mapboxSoundButton.setOnClickListener { - MapboxCarApp.carAppAudioGuidanceService().toggle() + MapboxAudioGuidance.getInstance().toggle() } } @@ -42,7 +43,7 @@ fun Lifecycle.muteAudioGuidance() { addObserver(object : DefaultLifecycleObserver { lateinit var initialState: MapboxAudioGuidanceState override fun onResume(owner: LifecycleOwner) { - with(MapboxCarApp.carAppAudioGuidanceService()) { + with(MapboxAudioGuidance.getInstance()) { initialState = stateFlow().value mute() } @@ -50,7 +51,7 @@ fun Lifecycle.muteAudioGuidance() { override fun onPause(owner: LifecycleOwner) { if (!initialState.isMuted) { - MapboxCarApp.carAppAudioGuidanceService().unMute() + MapboxAudioGuidance.getInstance().unMute() } } }) diff --git a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/CarAudioGuidanceUi.kt b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/CarAudioGuidanceUi.kt index e76207ea719..b7de2d7c121 100644 --- a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/CarAudioGuidanceUi.kt +++ b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/CarAudioGuidanceUi.kt @@ -12,6 +12,7 @@ import com.mapbox.androidauto.MapboxCarApp import com.mapbox.androidauto.R import com.mapbox.androidauto.car.MainActionStrip import com.mapbox.androidauto.car.action.MapboxActionProvider +import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch @@ -28,7 +29,7 @@ class CarAudioGuidanceUi : MapboxActionProvider.ScreenActionProvider { * Attach this to the screen while navigating. */ private fun buildSoundButtonAction(screen: Screen): Action { - val audioGuidance = MapboxCarApp.carAppAudioGuidanceService() + val audioGuidance = MapboxAudioGuidance.getInstance() val state = audioGuidance.stateFlow().value return if (!state.isMuted) { buildIconAction(screen, R.drawable.mapbox_car_ic_volume_on) { @@ -45,7 +46,7 @@ class CarAudioGuidanceUi : MapboxActionProvider.ScreenActionProvider { screen.lifecycle.apply { coroutineScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { - MapboxCarApp.carAppAudioGuidanceService().stateFlow() + MapboxAudioGuidance.getInstance().stateFlow() .distinctUntilChanged { old, new -> old.isMuted == new.isMuted && old.isPlayable == new.isPlayable } diff --git a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidance.kt b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidance.kt index cdf0285f57f..c845444d021 100644 --- a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidance.kt +++ b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidance.kt @@ -40,8 +40,6 @@ internal constructor( dispatcher: CoroutineDispatcher, ) : MapboxNavigationObserver { - constructor() : this(MapboxAudioGuidanceServices(), Dispatchers.Main) - private var dataStoreOwner: NavigationDataStoreOwner? = null private var configOwner: NavigationConfigOwner? = null private var mutedStateFlow = MutableStateFlow(false) @@ -197,9 +195,14 @@ internal constructor( dataStoreOwner?.write(STORE_AUDIO_GUIDANCE_MUTED, muted) } - private companion object { + companion object { private val STORE_AUDIO_GUIDANCE_MUTED = booleanDataStoreKey("audio_guidance_muted", false) private const val DEFAULT_DATA_STORE_NAME = "mapbox_navigation_preferences" + + fun getInstance(): MapboxAudioGuidance = MapboxNavigationApp + .getObservers(MapboxAudioGuidance::class) + .firstOrNull() ?: MapboxAudioGuidance(MapboxAudioGuidanceServices(), Dispatchers.Main) + .also { MapboxNavigationApp.registerObserver(it) } } } diff --git a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/installer/ComponentInstaller.kt b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/installer/ComponentInstaller.kt index f441ef86928..1e8b411dfdd 100644 --- a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/installer/ComponentInstaller.kt +++ b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/installer/ComponentInstaller.kt @@ -1,7 +1,6 @@ package com.mapbox.navigation.ui.voice.installer import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI -import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp import com.mapbox.navigation.ui.base.installer.ComponentInstaller import com.mapbox.navigation.ui.base.installer.Installation import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance @@ -17,13 +16,5 @@ import com.mapbox.navigation.ui.voice.view.MapboxAudioGuidanceButton */ @ExperimentalPreviewMapboxNavigationAPI fun ComponentInstaller.audioGuidanceButton(button: MapboxAudioGuidanceButton): Installation { - ensureAudioGuidanceRegistered() return component(AudioGuidanceButtonComponent(button)) } - -@ExperimentalPreviewMapboxNavigationAPI -private fun ensureAudioGuidanceRegistered() { - if (MapboxNavigationApp.getObservers(MapboxAudioGuidance::class).isEmpty()) { - MapboxNavigationApp.registerObserver(MapboxAudioGuidance()) - } -} diff --git a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponent.kt b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponent.kt index 28344855345..845aa6e32fb 100644 --- a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponent.kt +++ b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/internal/ui/AudioGuidanceButtonComponent.kt @@ -3,7 +3,6 @@ package com.mapbox.navigation.ui.voice.internal.ui import androidx.core.view.isVisible import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI import com.mapbox.navigation.core.MapboxNavigation -import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp import com.mapbox.navigation.ui.base.lifecycle.UIComponent import com.mapbox.navigation.ui.utils.internal.Provider import com.mapbox.navigation.ui.utils.internal.extensions.slice @@ -53,10 +52,7 @@ class AudioGuidanceButtonComponent( init { this.contractProvider = contractProvider ?: Provider { - val audioGuidance = MapboxNavigationApp - .getObservers(MapboxAudioGuidance::class).firstOrNull() - ?: MapboxAudioGuidance().also { MapboxNavigationApp.registerObserver(it) } - MapboxAudioComponentContract(coroutineScope, audioGuidance) + MapboxAudioComponentContract(coroutineScope, MapboxAudioGuidance.getInstance()) } } From d0b2790a4b569c093a63a892d4c06e4361bd1bd9 Mon Sep 17 00:00:00 2001 From: Kyle Madsen Date: Fri, 16 Sep 2022 18:29:58 -0700 Subject: [PATCH 4/6] Add provider functions --- .../audioguidance/AppAudioGuidanceUi.kt | 1 - .../audioguidance/CarAudioGuidanceUi.kt | 1 - libnavui-voice/api/current.txt | 9 +++++++- .../ui/voice/api/MapboxAudioGuidance.kt | 12 +++++++++- .../testing/JavaInterfaceChecker.java | 23 +++++++++++++++++++ 5 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/testing/JavaInterfaceChecker.java diff --git a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/AppAudioGuidanceUi.kt b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/AppAudioGuidanceUi.kt index 64c70091aef..d28071c908e 100644 --- a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/AppAudioGuidanceUi.kt +++ b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/AppAudioGuidanceUi.kt @@ -7,7 +7,6 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle -import com.mapbox.androidauto.MapboxCarApp import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidanceState import com.mapbox.navigation.ui.voice.view.MapboxSoundButton diff --git a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/CarAudioGuidanceUi.kt b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/CarAudioGuidanceUi.kt index b7de2d7c121..fdd81f34305 100644 --- a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/CarAudioGuidanceUi.kt +++ b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/audioguidance/CarAudioGuidanceUi.kt @@ -8,7 +8,6 @@ import androidx.core.graphics.drawable.IconCompat import androidx.lifecycle.Lifecycle import androidx.lifecycle.coroutineScope import androidx.lifecycle.repeatOnLifecycle -import com.mapbox.androidauto.MapboxCarApp import com.mapbox.androidauto.R import com.mapbox.androidauto.car.MainActionStrip import com.mapbox.androidauto.car.action.MapboxActionProvider diff --git a/libnavui-voice/api/current.txt b/libnavui-voice/api/current.txt index ce96ed7ece0..b1683029b86 100644 --- a/libnavui-voice/api/current.txt +++ b/libnavui-voice/api/current.txt @@ -22,13 +22,20 @@ package com.mapbox.navigation.ui.voice.api { } public final class MapboxAudioGuidance implements com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver { - ctor public MapboxAudioGuidance(); + method public static com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance create(); + method public static com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance getInstance(); method public void mute(); method public void onAttached(com.mapbox.navigation.core.MapboxNavigation mapboxNavigation); method public void onDetached(com.mapbox.navigation.core.MapboxNavigation mapboxNavigation); method public kotlinx.coroutines.flow.StateFlow stateFlow(); method public void toggle(); method public void unMute(); + field public static final com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance.Companion Companion; + } + + public static final class MapboxAudioGuidance.Companion { + method public com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance create(); + method public com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance getInstance(); } public final class MapboxAudioGuidanceState { diff --git a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidance.kt b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidance.kt index c845444d021..e22eba37ba2 100644 --- a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidance.kt +++ b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidance.kt @@ -200,9 +200,19 @@ internal constructor( booleanDataStoreKey("audio_guidance_muted", false) private const val DEFAULT_DATA_STORE_NAME = "mapbox_navigation_preferences" + /** + * Construct an instance without registering to [MapboxNavigationApp]. + */ + @JvmStatic + fun create() = MapboxAudioGuidance(MapboxAudioGuidanceServices(), Dispatchers.Main) + + /** + * Get the registered instance or create one and register it to [MapboxNavigationApp]. + */ + @JvmStatic fun getInstance(): MapboxAudioGuidance = MapboxNavigationApp .getObservers(MapboxAudioGuidance::class) - .firstOrNull() ?: MapboxAudioGuidance(MapboxAudioGuidanceServices(), Dispatchers.Main) + .firstOrNull() ?: create() .also { MapboxNavigationApp.registerObserver(it) } } } diff --git a/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/testing/JavaInterfaceChecker.java b/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/testing/JavaInterfaceChecker.java new file mode 100644 index 00000000000..2cb5dfa0947 --- /dev/null +++ b/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/testing/JavaInterfaceChecker.java @@ -0,0 +1,23 @@ +package com.mapbox.navigation.qa_test_app.testing; + +import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp; +import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance; + +import kotlinx.coroutines.CoroutineScope; + +class JavaInterfaceChecker { + + void MapboxAudioGuidance( + CoroutineScope coroutineScope + ) { + MapboxAudioGuidance sut = MapboxAudioGuidance.getInstance(); + sut.mute(); + sut.unMute(); + sut.toggle(); + MapboxNavigationApp.registerObserver(sut); + MapboxNavigationApp.unregisterObserver(sut); + JavaFlow.collect(sut.stateFlow(), coroutineScope, (enabled) -> { + // observe state + }); + } +} From 8265dd055851420afaae8faa0351cdb27ed11831 Mon Sep 17 00:00:00 2001 From: Kyle Madsen Date: Mon, 19 Sep 2022 12:25:01 -0700 Subject: [PATCH 5/6] fix test --- .../com/mapbox/androidauto/MapboxCarApp.kt | 1 - .../AudioGuidanceStateController.kt | 3 +-- .../AudioGuidanceStateControllerTest.kt | 19 +++++-------------- .../ui/voice/api/MapboxAudioGuidance.kt | 3 +-- 4 files changed, 7 insertions(+), 19 deletions(-) diff --git a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/MapboxCarApp.kt b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/MapboxCarApp.kt index 6cc45fcfa61..2dbb1bff82d 100644 --- a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/MapboxCarApp.kt +++ b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/MapboxCarApp.kt @@ -4,7 +4,6 @@ import com.mapbox.androidauto.navigation.location.CarAppLocation import com.mapbox.androidauto.navigation.location.impl.CarAppLocationImpl import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp -import com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow diff --git a/libnavui-app/src/main/java/com/mapbox/navigation/ui/app/internal/controller/AudioGuidanceStateController.kt b/libnavui-app/src/main/java/com/mapbox/navigation/ui/app/internal/controller/AudioGuidanceStateController.kt index 26ce94a1e82..4d48fdaefeb 100644 --- a/libnavui-app/src/main/java/com/mapbox/navigation/ui/app/internal/controller/AudioGuidanceStateController.kt +++ b/libnavui-app/src/main/java/com/mapbox/navigation/ui/app/internal/controller/AudioGuidanceStateController.kt @@ -2,7 +2,6 @@ package com.mapbox.navigation.ui.app.internal.controller import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI import com.mapbox.navigation.core.MapboxNavigation -import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp import com.mapbox.navigation.ui.app.internal.Action import com.mapbox.navigation.ui.app.internal.State import com.mapbox.navigation.ui.app.internal.Store @@ -47,7 +46,7 @@ class AudioGuidanceStateController( override fun onAttached(mapboxNavigation: MapboxNavigation) { super.onAttached(mapboxNavigation) - val audioGuidance = MapboxNavigationApp.getObserver(MapboxAudioGuidance::class) + val audioGuidance = MapboxAudioGuidance.getInstance() audioGuidance.stateFlow().observe { if (it.isMuted != store.state.value.audio.isMuted) { val newState = AudioGuidanceState(it.isMuted) diff --git a/libnavui-app/src/test/java/com/mapbox/navigation/ui/app/internal/controller/AudioGuidanceStateControllerTest.kt b/libnavui-app/src/test/java/com/mapbox/navigation/ui/app/internal/controller/AudioGuidanceStateControllerTest.kt index 72c845349a9..a9c9132bb4d 100644 --- a/libnavui-app/src/test/java/com/mapbox/navigation/ui/app/internal/controller/AudioGuidanceStateControllerTest.kt +++ b/libnavui-app/src/test/java/com/mapbox/navigation/ui/app/internal/controller/AudioGuidanceStateControllerTest.kt @@ -1,7 +1,6 @@ package com.mapbox.navigation.ui.app.internal.controller import com.mapbox.navigation.core.MapboxNavigation -import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp import com.mapbox.navigation.testing.MainCoroutineRule import com.mapbox.navigation.ui.app.internal.State import com.mapbox.navigation.ui.app.internal.audioguidance.AudioAction @@ -37,7 +36,7 @@ class AudioGuidanceStateControllerTest { @Before fun setup() { - mockkObject(MapboxNavigationApp) + mockkObject(MapboxAudioGuidance) audioGuidanceState = MutableStateFlow( mockk { every { isMuted } returns false } @@ -45,9 +44,7 @@ class AudioGuidanceStateControllerTest { mockAudioGuidance = mockk(relaxed = true) { every { stateFlow() } returns audioGuidanceState } - every { - MapboxNavigationApp.getObserver(MapboxAudioGuidance::class) - } returns mockAudioGuidance + every { MapboxAudioGuidance.getInstance() } returns mockAudioGuidance testStore = spyk(TestStore()) } @@ -68,7 +65,7 @@ class AudioGuidanceStateControllerTest { ) audioGuidanceState.value = mockk { every { isMuted } returns true } - sut.onAttached(mockMapboxNavigation()) + sut.onAttached(mockk()) assertTrue(testStore.state.value.audio.isMuted) } @@ -83,7 +80,7 @@ class AudioGuidanceStateControllerTest { ) audioGuidanceState.value = mockk { every { isMuted } returns false } - sut.onAttached(mockMapboxNavigation()) + sut.onAttached(mockk()) testStore.setState( State( audio = AudioGuidanceState(isMuted = true) @@ -103,17 +100,11 @@ class AudioGuidanceStateControllerTest { ) val sut = AudioGuidanceStateController(testStore) - val mapboxNavigation = mockMapboxNavigation() + val mapboxNavigation: MapboxNavigation = mockk() sut.onAttached(mapboxNavigation) testStore.dispatch(AudioAction.Toggle) sut.onDetached(mapboxNavigation) assertTrue(testStore.state.value.audio.isMuted) } - - private fun mockMapboxNavigation(): MapboxNavigation { - val mapboxNavigation = mockk(relaxed = true) - every { MapboxNavigationApp.current() } returns mapboxNavigation - return mapboxNavigation - } } diff --git a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidance.kt b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidance.kt index e22eba37ba2..517593ceaea 100644 --- a/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidance.kt +++ b/libnavui-voice/src/main/java/com/mapbox/navigation/ui/voice/api/MapboxAudioGuidance.kt @@ -212,7 +212,6 @@ internal constructor( @JvmStatic fun getInstance(): MapboxAudioGuidance = MapboxNavigationApp .getObservers(MapboxAudioGuidance::class) - .firstOrNull() ?: create() - .also { MapboxNavigationApp.registerObserver(it) } + .firstOrNull() ?: create().also { MapboxNavigationApp.registerObserver(it) } } } From 298f80de49de8d709ad0d3f28d2a3fdd7f706f4e Mon Sep 17 00:00:00 2001 From: Kyle Madsen Date: Mon, 19 Sep 2022 14:41:57 -0700 Subject: [PATCH 6/6] update api --- libnavui-androidauto/api/current.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/libnavui-androidauto/api/current.txt b/libnavui-androidauto/api/current.txt index fa947e6def3..57f216d9e78 100644 --- a/libnavui-androidauto/api/current.txt +++ b/libnavui-androidauto/api/current.txt @@ -17,7 +17,6 @@ package com.mapbox.androidauto { } public final class MapboxCarApp { - method public com.mapbox.navigation.ui.voice.api.MapboxAudioGuidance carAppAudioGuidanceService(); method public com.mapbox.androidauto.navigation.location.CarAppLocation carAppLocationService(); method public kotlinx.coroutines.flow.StateFlow getCarAppState(); method public void setup();