Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,12 @@ private constructor(private val navigationSessionEventApi: NavigationSessionEven
RoadSnappedLocationProvider.GpsAvailabilityEnhancedLocationListener? =
null
private var speedingListener: SpeedingListener? = null
private var navigationSessionListener: Navigator.NavigationSessionListener? = null
private var weakActivity: WeakReference<Activity>? = null
private var turnByTurnEventsEnabled: Boolean = false
private var weakLifecycleOwner: WeakReference<LifecycleOwner>? = null
private var taskRemovedBehavior: @TaskRemovedBehavior Int = 0
private var isGuidanceNotificationsEnabled: Boolean = true

override fun onCreate(owner: LifecycleOwner) {
weakLifecycleOwner = WeakReference(owner)
Expand Down Expand Up @@ -331,6 +333,10 @@ private constructor(private val navigationSessionEventApi: NavigationSessionEven
navigator.setSpeedingListener(null)
speedingListener = null
}
if (navigationSessionListener != null) {
navigator.removeNavigationSessionListener(navigationSessionListener)
navigationSessionListener = null
}
}
if (roadSnappedLocationListener != null) {
disableRoadSnappedLocationUpdates()
Expand Down Expand Up @@ -407,6 +413,16 @@ private constructor(private val navigationSessionEventApi: NavigationSessionEven
}
navigator.setSpeedingListener(speedingListener)
}

if (navigationSessionListener == null) {
navigationSessionListener =
object : Navigator.NavigationSessionListener {
override fun onNewNavigationSession() {
navigationSessionEventApi.onNewNavigationSession {}
}
}
navigator.addNavigationSessionListener(navigationSessionListener)
}
}

/**
Expand Down Expand Up @@ -511,6 +527,32 @@ private constructor(private val navigationSessionEventApi: NavigationSessionEven
getNavigator().setAudioGuidance(audioGuidanceSettings)
}

/**
* Sets whether guidance notifications should be shown when the app is not in the foreground. On
* Android, this controls heads-up notifications for guidance events (turns, etc.). On iOS, this
* controls background notifications containing guidance information.
*
* This method must be called on the UI thread. Wraps [Navigator.setHeadsUpNotificationEnabled].
* See
* [Google Navigation SDK for Android](https://developers.google.com/maps/documentation/navigation/android-sdk/reference/com/google/android/libraries/navigation/Navigator#setHeadsUpNotificationEnabled(boolean)).
*/
@Throws(FlutterError::class)
fun setGuidanceNotificationsEnabled(enabled: Boolean) {
isGuidanceNotificationsEnabled = enabled
val activity = getActivity()
activity.runOnUiThread { getNavigator().setHeadsUpNotificationEnabled(enabled) }
}

/**
* Gets whether guidance notifications are enabled. On Android, returns the state of heads-up
* notifications. On iOS, returns the state of background notifications.
*
* @return true if guidance notifications are enabled, false otherwise.
*/
fun getGuidanceNotificationsEnabled(): Boolean {
return isGuidanceNotificationsEnabled
}

fun setSpeedAlertOptions(options: SpeedAlertOptions) {
getNavigator().setSpeedAlertOptions(options)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,14 @@ class GoogleMapsNavigationSessionMessageHandler : NavigationSessionApi {
manager().setAudioGuidance(audioGuidanceSettings)
}

override fun setGuidanceNotificationsEnabled(enabled: Boolean) {
manager().setGuidanceNotificationsEnabled(enabled)
}

override fun getGuidanceNotificationsEnabled(): Boolean {
return manager().getGuidanceNotificationsEnabled()
}

override fun setSpeedAlertOptions(options: SpeedAlertOptionsDto) {
val newOptions = Convert.convertSpeedAlertOptionsFromDto(options)
manager().setSpeedAlertOptions(newOptions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5693,7 +5693,6 @@ class ViewEventApi(

/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface NavigationSessionApi {
/** General. */
fun createNavigationSession(
abnormalTerminationReportingEnabled: Boolean,
behavior: TaskRemovedBehaviorDto,
Expand All @@ -5717,7 +5716,6 @@ interface NavigationSessionApi {

fun getNavSDKVersion(): String

/** Navigation. */
fun isGuidanceRunning(): Boolean

fun startGuidance()
Expand All @@ -5742,7 +5740,10 @@ interface NavigationSessionApi {

fun getCurrentRouteSegment(): RouteSegmentDto?

/** Simulation */
fun setGuidanceNotificationsEnabled(enabled: Boolean)

fun getGuidanceNotificationsEnabled(): Boolean

fun setUserLocation(location: LatLngDto)

fun removeUserLocation()
Expand Down Expand Up @@ -5773,15 +5774,13 @@ interface NavigationSessionApi {

fun resumeSimulation()

/** Simulation (iOS only) */
/** iOS-only method. */
fun allowBackgroundLocationUpdates(allow: Boolean)

/** Road snapped location updates. */
fun enableRoadSnappedLocationUpdates()

fun disableRoadSnappedLocationUpdates()

/** Enable Turn-by-Turn navigation events. */
fun enableTurnByTurnNavigationEvents(numNextStepsToPreview: Long?)

fun disableTurnByTurnNavigationEvents()
Expand Down Expand Up @@ -6236,6 +6235,51 @@ interface NavigationSessionApi {
channel.setMessageHandler(null)
}
}
run {
val channel =
BasicMessageChannel<Any?>(
binaryMessenger,
"dev.flutter.pigeon.google_navigation_flutter.NavigationSessionApi.setGuidanceNotificationsEnabled$separatedMessageChannelSuffix",
codec,
)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val enabledArg = args[0] as Boolean
val wrapped: List<Any?> =
try {
api.setGuidanceNotificationsEnabled(enabledArg)
listOf(null)
} catch (exception: Throwable) {
MessagesPigeonUtils.wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel =
BasicMessageChannel<Any?>(
binaryMessenger,
"dev.flutter.pigeon.google_navigation_flutter.NavigationSessionApi.getGuidanceNotificationsEnabled$separatedMessageChannelSuffix",
codec,
)
if (api != null) {
channel.setMessageHandler { _, reply ->
val wrapped: List<Any?> =
try {
listOf(api.getGuidanceNotificationsEnabled())
} catch (exception: Throwable) {
MessagesPigeonUtils.wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel =
BasicMessageChannel<Any?>(
Expand Down Expand Up @@ -6808,6 +6852,26 @@ class NavigationSessionEventApi(
}
}
}

/** Navigation session event. Called when a new navigation session starts with active guidance. */
fun onNewNavigationSession(callback: (Result<Unit>) -> Unit) {
val separatedMessageChannelSuffix =
if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
val channelName =
"dev.flutter.pigeon.google_navigation_flutter.NavigationSessionEventApi.onNewNavigationSession$separatedMessageChannelSuffix"
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
channel.send(null) {
if (it is List<*>) {
if (it.size > 1) {
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
} else {
callback(Result.success(Unit))
}
} else {
callback(Result.failure(MessagesPigeonUtils.createConnectionError(channelName)))
}
}
}
}

/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
Expand Down
86 changes: 64 additions & 22 deletions example/integration_test/t03_navigation_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,22 +59,12 @@ void main() {
PatrolIntegrationTester $,
) async {
final Completer<void> hasArrived = Completer<void>();
final Completer<void> newSessionFired = Completer<void>();

/// Set up navigation view and controller.
final GoogleNavigationViewController viewController =
await startNavigationWithoutDestination($);

/// Set audio guidance settings.
/// Cannot be verified, because native SDK lacks getter methods,
/// but exercise the API for basic sanity testing
final NavigationAudioGuidanceSettings settings =
NavigationAudioGuidanceSettings(
isBluetoothAudioEnabled: true,
isVibrationEnabled: true,
guidanceType: NavigationAudioGuidanceType.alertsAndGuidance,
);
await GoogleMapsNavigator.setAudioGuidance(settings);

/// Specify tolerance and navigation end coordinates.
const double tolerance = 0.001;
const double endLat = 68.59451829688189, endLng = 23.512277951523007;
Expand All @@ -86,7 +76,26 @@ void main() {
await GoogleMapsNavigator.stopGuidance();
}

/// Set up listener for new navigation session event.
Future<void> onNewNavigationSession() async {
newSessionFired.complete();

/// Sets audio guidance settings for the current navigation session.
/// Cannot be verified, because native SDK lacks getter methods,
/// but exercise the API for basic sanity testing.
await GoogleMapsNavigator.setAudioGuidance(
NavigationAudioGuidanceSettings(
isBluetoothAudioEnabled: true,
isVibrationEnabled: true,
guidanceType: NavigationAudioGuidanceType.alertsAndGuidance,
),
);
}

GoogleMapsNavigator.setOnArrivalListener(onArrivalEvent);
GoogleMapsNavigator.setOnNewNavigationSessionListener(
onNewNavigationSession,
);

/// Simulate location and test it.
await setSimulatedUserLocationWithCheck(
Expand Down Expand Up @@ -140,6 +149,18 @@ void main() {
await GoogleMapsNavigator.simulator.simulateLocationsAlongExistingRoute();

expect(await GoogleMapsNavigator.isGuidanceRunning(), true);

/// Wait for new navigation session event.
await newSessionFired.future.timeout(
const Duration(seconds: 30),
onTimeout:
() =>
throw TimeoutException(
'New navigation session event was not fired',
),
);
expect(newSessionFired.isCompleted, true);

await hasArrived.future;
expect(await GoogleMapsNavigator.isGuidanceRunning(), false);

Expand All @@ -150,24 +171,14 @@ void main() {
'Test navigating to multiple destinations',
(PatrolIntegrationTester $) async {
final Completer<void> navigationFinished = Completer<void>();
final Completer<void> newSessionFired = Completer<void>();
int arrivalEventCount = 0;
List<NavigationWaypoint> waypoints = <NavigationWaypoint>[];

/// Set up navigation view and controller.
final GoogleNavigationViewController viewController =
await startNavigationWithoutDestination($);

/// Set audio guidance settings.
/// Cannot be verified, because native SDK lacks getter methods,
/// but exercise the API for basic sanity testing
final NavigationAudioGuidanceSettings settings =
NavigationAudioGuidanceSettings(
isBluetoothAudioEnabled: false,
isVibrationEnabled: false,
guidanceType: NavigationAudioGuidanceType.alertsOnly,
);
await GoogleMapsNavigator.setAudioGuidance(settings);

/// Specify tolerance and navigation destination coordinates.
const double tolerance = 0.001;
const double midLat = 68.59781164189049,
Expand Down Expand Up @@ -228,7 +239,26 @@ void main() {
}
}

/// Set up listener for new navigation session event.
Future<void> onNewNavigationSession() async {
newSessionFired.complete();

/// Sets audio guidance settings for the current navigation session.
/// Cannot be verified, because native SDK lacks getter methods,
/// but exercise the API for basic sanity testing.
await GoogleMapsNavigator.setAudioGuidance(
NavigationAudioGuidanceSettings(
isBluetoothAudioEnabled: true,
isVibrationEnabled: true,
guidanceType: NavigationAudioGuidanceType.alertsAndGuidance,
),
);
}

GoogleMapsNavigator.setOnArrivalListener(onArrivalEvent);
GoogleMapsNavigator.setOnNewNavigationSessionListener(
onNewNavigationSession,
);

/// Simulate location and test it.
await setSimulatedUserLocationWithCheck(
Expand Down Expand Up @@ -308,6 +338,18 @@ void main() {
);

expect(await GoogleMapsNavigator.isGuidanceRunning(), true);

/// Wait for new navigation session event.
await newSessionFired.future.timeout(
const Duration(seconds: 30),
onTimeout:
() =>
throw TimeoutException(
'New navigation session event was not fired',
),
);
expect(newSessionFired.isCompleted, true);

await navigationFinished.future;
expect(await GoogleMapsNavigator.isGuidanceRunning(), false);

Expand Down
Loading
Loading