Skip to content
Merged
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 @@ -70,6 +70,7 @@ constructor(
RoadSnappedLocationProvider.GpsAvailabilityEnhancedLocationListener? =
null
private var speedingListener: SpeedingListener? = null
private var navigationSessionListener: Navigator.NavigationSessionListener? = null
private var weakActivity: WeakReference<Activity>? = null
private var navInfoObserver: Observer<NavInfo>? = null
private var weakLifecycleOwner: WeakReference<LifecycleOwner>? = null
Expand Down Expand Up @@ -315,6 +316,10 @@ constructor(
navigator.setSpeedingListener(null)
speedingListener = null
}
if (navigationSessionListener != null) {
navigator.removeNavigationSessionListener(navigationSessionListener)
navigationSessionListener = null
}
}
if (roadSnappedLocationListener != null) {
disableRoadSnappedLocationUpdates()
Expand Down Expand Up @@ -391,6 +396,12 @@ constructor(
}
navigator.setSpeedingListener(speedingListener)
}

if (navigationSessionListener == null) {
navigationSessionListener =
Navigator.NavigationSessionListener { navigationSessionEventApi.onNewNavigationSession {} }
navigator.addNavigationSessionListener(navigationSessionListener)
}
}

/**
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,6 @@ interface NavigationSessionApi {

fun getCurrentRouteSegment(): RouteSegmentDto?

/** Simulation */
fun setUserLocation(location: LatLngDto)

fun removeUserLocation()
Expand Down Expand Up @@ -5773,15 +5770,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 @@ -6810,6 +6805,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
104 changes: 82 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,8 +76,28 @@ 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,
),
);
}

final StreamSubscription<OnArrivalEvent> onArrivalSubscription =
GoogleMapsNavigator.setOnArrivalListener(onArrivalEvent);
final StreamSubscription<void> onNewNavigationSessionSubscription =
GoogleMapsNavigator.setOnNewNavigationSessionListener(
onNewNavigationSession,
);

/// Simulate location and test it.
await setSimulatedUserLocationWithCheck(
Expand Down Expand Up @@ -143,11 +153,24 @@ 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);

// Cancel subscriptions before cleanup
await onArrivalSubscription.cancel();
await onNewNavigationSessionSubscription.cancel();
await roadSnappedSubscription.cancel();
await GoogleMapsNavigator.cleanup();
});
Expand All @@ -156,24 +179,14 @@ void main() {
'Test navigating to multiple destinations',
(PatrolIntegrationTester $) async {
final Completer<void> navigationFinished = Completer<void>();
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 All @@ -184,6 +197,9 @@ void main() {
Future<void> onArrivalEvent(OnArrivalEvent msg) async {
arrivalEventCount += 1;
if (arrivalEventCount < 2) {
// Reset the completer to test that new session event fires again
newSessionFired = Completer<void>();

if (multipleDestinationsVariants.currentValue ==
'continueToNextDestination') {
// Note: continueToNextDestination is deprecated.
Expand Down Expand Up @@ -220,12 +236,23 @@ void main() {
),
);
await GoogleMapsNavigator.setDestinations(updatedDestinations);

await GoogleMapsNavigator.simulator
.simulateLocationsAlongExistingRouteWithOptions(
SimulationOptions(speedMultiplier: 5),
);
}
}

// Wait for new session event after updating destinations
await newSessionFired.future.timeout(
const Duration(seconds: 10),
onTimeout:
() =>
throw TimeoutException(
'New navigation session event was not fired after updating destinations',
),
);
} else {
$.log('Got second arrival event, stopping guidance');
// Stop guidance after the last destination
Expand All @@ -234,8 +261,28 @@ 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,
),
);
}

final StreamSubscription<OnArrivalEvent> onArrivalSubscription =
GoogleMapsNavigator.setOnArrivalListener(onArrivalEvent);
final StreamSubscription<void> onNewNavigationSessionSubscription =
GoogleMapsNavigator.setOnNewNavigationSessionListener(
onNewNavigationSession,
);

/// Simulate location and test it.
await setSimulatedUserLocationWithCheck(
Expand Down Expand Up @@ -317,11 +364,24 @@ 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);

// Cancel subscriptions before cleanup
await onArrivalSubscription.cancel();
await onNewNavigationSessionSubscription.cancel();
await roadSnappedSubscription.cancel();
await GoogleMapsNavigator.cleanup();
},
Expand Down
43 changes: 43 additions & 0 deletions example/lib/pages/navigation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class _NavigationPageState extends ExamplePageState<NavigationPage> {
int _onRecenterButtonClickedEventCallCount = 0;
int _onRemainingTimeOrDistanceChangedEventCallCount = 0;
int _onNavigationUIEnabledChangedEventCallCount = 0;
int _onNewNavigationSessionEventCallCount = 0;

bool _navigationHeaderEnabled = true;
bool _navigationFooterEnabled = true;
Expand Down Expand Up @@ -147,6 +148,7 @@ class _NavigationPageState extends ExamplePageState<NavigationPage> {
_roadSnappedLocationUpdatedSubscription;
StreamSubscription<RoadSnappedRawLocationUpdatedEvent>?
_roadSnappedRawLocationUpdatedSubscription;
StreamSubscription<void>? _newNavigationSessionSubscription;

int _nextWaypointIndex = 0;

Expand Down Expand Up @@ -379,6 +381,11 @@ class _NavigationPageState extends ExamplePageState<NavigationPage> {
await GoogleMapsNavigator.setRoadSnappedRawLocationUpdatedListener(
_onRoadSnappedRawLocationUpdatedEvent,
);

_newNavigationSessionSubscription =
GoogleMapsNavigator.setOnNewNavigationSessionListener(
_onNewNavigationSessionEvent,
);
}

void _clearListeners() {
Expand Down Expand Up @@ -408,6 +415,24 @@ class _NavigationPageState extends ExamplePageState<NavigationPage> {

_roadSnappedRawLocationUpdatedSubscription?.cancel();
_roadSnappedRawLocationUpdatedSubscription = null;

_newNavigationSessionSubscription?.cancel();
_newNavigationSessionSubscription = null;
}

void _onNewNavigationSessionEvent() {
if (!mounted) {
return;
}

setState(() {
_onNewNavigationSessionEventCallCount += 1;
});

showMessage('New navigation session started');

// Set audio guidance settings for the new navigation session.
unawaited(_setAudioGuidance());
}

void _onRoadSnappedLocationUpdatedEvent(
Expand Down Expand Up @@ -517,6 +542,16 @@ class _NavigationPageState extends ExamplePageState<NavigationPage> {
await _getInitialViewStates();
}

Future<void> _setAudioGuidance() async {
await GoogleMapsNavigator.setAudioGuidance(
NavigationAudioGuidanceSettings(
isBluetoothAudioEnabled: true,
isVibrationEnabled: true,
guidanceType: NavigationAudioGuidanceType.alertsAndGuidance,
),
);
}

Future<void> _getInitialViewStates() async {
assert(_navigationViewController != null);
if (_navigationViewController != null) {
Expand Down Expand Up @@ -1445,6 +1480,14 @@ class _NavigationPageState extends ExamplePageState<NavigationPage> {
),
),
),
Card(
child: ListTile(
title: const Text('New navigation session event call count'),
trailing: Text(
_onNewNavigationSessionEventCallCount.toString(),
),
),
),
],
),
);
Expand Down
Loading
Loading