Skip to content
Open
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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,8 @@ const {
| `getCurrentRouteSegment()` | `Promise<RouteSegment \| null>` | Get the current route segment |
| `getRouteSegments()` | `Promise<RouteSegment[]>` | Get all route segments |
| `getTraveledPath()` | `Promise<LatLng[]>` | Get the path traveled so far |
| `setAudioGuidanceType(type: AudioGuidanceType)` | `Promise<void>` | Set audio guidance type (SILENT, ALERTS_ONLY, VOICE_ALERTS_AND_GUIDANCE) |
| `setAudioGuidanceType(type: AudioGuidance)` | `Promise<void>` | Deprecated. Set the voice guidance mode only |
| `setAudioGuidanceSettings(settings: AudioGuidanceSettings)` | `Promise<void>` | Set voice guidance mode and enable/disable vibration and Bluetooth audio |
| `setSpeedAlertOptions(options: SpeedAlertOptions)` | `Promise<void>` | Configure speed alert thresholds |
| `setAbnormalTerminatingReportingEnabled(enabled: boolean)` | `void` | Enable/disable abnormal termination reporting |
| `startUpdatingLocation()` | `Promise<void>` | Start receiving location updates |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,36 @@ public void setAudioGuidanceType(double index, final Promise promise) {
promise.resolve(null);
}

@Override
public void setAudioGuidanceSettings(@NonNull ReadableMap settings, final Promise promise) {
if (mNavigator == null) {
promise.reject(JsErrors.NO_NAVIGATOR_ERROR_CODE, JsErrors.NO_NAVIGATOR_ERROR_MESSAGE);
return;
}
if (!settings.hasKey("guidanceMode")
|| !settings.hasKey("vibrationEnabled")
|| !settings.hasKey("bluetoothAudioEnabled")) {
promise.reject(JsErrors.INVALID_OPTIONS_ERROR_CODE, "Invalid audio guidance settings.");
return;
}

int guidanceMode = (int) settings.getDouble("guidanceMode");
boolean vibrationEnabled = settings.getBoolean("vibrationEnabled");
boolean bluetoothAudioEnabled = settings.getBoolean("bluetoothAudioEnabled");

UiThreadUtil.runOnUiThread(
() -> {
mNavigator.setAudioGuidanceSettings(
AudioGuidanceSettings.builder()
.setGuidanceMode(
EnumTranslationUtil.getAudioGuidanceModeFromJsValue(guidanceMode))
.setVibrationEnabled(vibrationEnabled)
.setBluetoothAudioEnabled(bluetoothAudioEnabled)
.build());
});
promise.resolve(null);
}

@Override
public void getCurrentTimeAndDistance(final Promise promise) {
if (mNavigator == null) {
Expand Down
60 changes: 56 additions & 4 deletions example/src/controls/navigationControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { ExampleAppButton } from './ExampleAppButton';
import { Accordion } from './Accordion';
import { showSnackbar, Snackbar } from '../helpers/snackbar';
import {
AudioGuidanceMode,
CameraPerspective,
NavigationNightMode,
type NavigationViewController,
Expand Down Expand Up @@ -87,6 +88,11 @@ const NavigationControls: React.FC<NavigationControlsProps> = ({
: 0;
const nightModeLabel = nightModeOptions[nightModeIndex];
const audioGuidanceOptions = ['Silent', 'Alerts only', 'Alerts and guidance'];
const [audioGuidanceMode, setAudioGuidanceMode] = useState(
AudioGuidanceMode.VOICE_ALERTS_AND_GUIDANCE
);
const [vibrationEnabled, setVibrationEnabled] = useState(false);
const [bluetoothAudioEnabled, setBluetoothAudioEnabled] = useState(false);
const [tripProgressBarEnabled, setTripProgressBarEnabled] = useState(false);
const [reportIncidentButtonEnabled, setReportIncidentButtonEnabled] =
useState(true);
Expand Down Expand Up @@ -309,8 +315,23 @@ const NavigationControls: React.FC<NavigationControlsProps> = ({
onNavigationNightModeChange?.(mode);
};

const setAudioGuidanceType = (index: number) => {
navigationController.setAudioGuidanceType(index);
const setAudioGuidanceSettings = async (
guidanceMode: AudioGuidanceMode,
isVibrationEnabled: boolean,
isBluetoothAudioEnabled: boolean
) => {
try {
await navigationController.setAudioGuidanceSettings({
guidanceMode,
vibrationEnabled: isVibrationEnabled,
bluetoothAudioEnabled: isBluetoothAudioEnabled,
});
setAudioGuidanceMode(guidanceMode);
setVibrationEnabled(isVibrationEnabled);
setBluetoothAudioEnabled(isBluetoothAudioEnabled);
} catch (e) {
showSnackbar(`Error setting audio guidance: ${e}`);
}
};

const getCurrentRouteSegment = async () => {
Expand Down Expand Up @@ -681,11 +702,15 @@ const NavigationControls: React.FC<NavigationControlsProps> = ({
{/* Audio & Logging */}
<Accordion title="Audio & Logging">
<View style={ControlStyles.rowContainer}>
<Text style={ControlStyles.rowLabel}>Audio guidance type</Text>
<Text style={ControlStyles.rowLabel}>Audio guidance mode</Text>
<SelectDropdown
data={audioGuidanceOptions}
onSelect={(_selectedItem, index) => {
setAudioGuidanceType(index);
setAudioGuidanceSettings(
index as AudioGuidanceMode,
vibrationEnabled,
bluetoothAudioEnabled
);
}}
renderButton={(selectedItem, _isOpened) => {
return (
Expand All @@ -708,9 +733,36 @@ const NavigationControls: React.FC<NavigationControlsProps> = ({
</View>
);
}}
defaultValue={audioGuidanceOptions[audioGuidanceMode]}
dropdownStyle={ControlStyles.dropdownMenu}
/>
</View>
<View style={ControlStyles.rowContainer}>
<Text style={ControlStyles.rowLabel}>Vibration</Text>
<ExampleAppButton
title={vibrationEnabled ? 'Disable' : 'Enable'}
onPress={() => {
setAudioGuidanceSettings(
audioGuidanceMode,
!vibrationEnabled,
bluetoothAudioEnabled
);
}}
/>
</View>
<View style={ControlStyles.rowContainer}>
<Text style={ControlStyles.rowLabel}>Bluetooth audio</Text>
<ExampleAppButton
title={bluetoothAudioEnabled ? 'Disable' : 'Enable'}
onPress={() => {
setAudioGuidanceSettings(
audioGuidanceMode,
vibrationEnabled,
!bluetoothAudioEnabled
);
}}
/>
</View>
<View style={ControlStyles.rowContainer}>
<Text style={ControlStyles.rowLabel}>Turn-by-turn logging</Text>
<ExampleAppButton
Expand Down
11 changes: 7 additions & 4 deletions example/src/screens/integration_tests/integration_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

import {
AudioGuidance,
AudioGuidanceMode,
CameraPerspective,
TravelMode,
NavigationSessionStatus,
Expand Down Expand Up @@ -181,9 +181,12 @@ const waitForTimeAndDistance = async (

const disableVoiceGuidanceForTests = (
navigationController: NavigationController
) => {
navigationController.setAudioGuidanceType(AudioGuidance.SILENT);
};
) =>
navigationController.setAudioGuidanceSettings({
guidanceMode: AudioGuidanceMode.SILENT,
vibrationEnabled: false,
bluetoothAudioEnabled: false,
});

const LOCATION_THRESHOLD_METERS = 100;
const LOCATION_WAIT_TIMEOUT_MS = 15000;
Expand Down
30 changes: 30 additions & 0 deletions ios/react-native-navigation-sdk/NavModule.mm
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,36 @@ - (void)setAudioGuidanceType:(double)index
});
}

- (void)setAudioGuidanceSettings:(AudioGuidanceSettingsSpec &)settings
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject {
AudioGuidanceSettingsSpec settingsCopy(settings);
dispatch_async(dispatch_get_main_queue(), ^{
GMSNavigator *navigator = nil;
if (![self checkNavigatorWithError:reject navigator:&navigator]) {
return;
}

double guidanceMode = settingsCopy.guidanceMode();
if (guidanceMode == 0) {
navigator.voiceGuidance = GMSNavigationVoiceGuidanceSilent;
} else if (guidanceMode == 1) {
navigator.voiceGuidance = GMSNavigationVoiceGuidanceAlertsOnly;
} else if (guidanceMode == 2) {
navigator.voiceGuidance = GMSNavigationVoiceGuidanceAlertsAndGuidance;
} else {
reject(@"INVALID_OPTIONS", @"Invalid audio guidance mode.", nil);
return;
}

navigator.vibrationEnabled = settingsCopy.vibrationEnabled();
navigator.audioDeviceType = settingsCopy.bluetoothAudioEnabled()
? GMSVoiceGuidanceAudioDeviceTypeBluetooth
: GMSVoiceGuidanceAudioDeviceTypeBuiltInOnly;
resolve(@(YES));
});
}

- (void)startGuidance:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
dispatch_async(dispatch_get_main_queue(), ^{
GMSNavigator *navigator = nil;
Expand Down
7 changes: 7 additions & 0 deletions src/native/NativeNavModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ type LocationSimulationOptionsSpec = Readonly<{
readonly speedMultiplier: Float;
}>;

type AudioGuidanceSettingsSpec = Readonly<{
guidanceMode: Double;
vibrationEnabled: boolean;
bluetoothAudioEnabled: boolean;
}>;

type ArrivalEventSpec = Readonly<{
waypoint: WaypointSpec;
isFinalDestination?: boolean;
Expand Down Expand Up @@ -186,6 +192,7 @@ export interface Spec extends TurboModule {
setSpeedAlertOptions(alertOptions: SpeedAlertOptionsSpec): Promise<void>;
setAbnormalTerminatingReportingEnabled(enabled: boolean): void;
setAudioGuidanceType(index: Double): Promise<void>;
setAudioGuidanceSettings(settings: AudioGuidanceSettingsSpec): Promise<void>;
setBackgroundLocationUpdatesEnabled(isEnabled: boolean): void;
setTurnByTurnLoggingEnabled(isEnabled: boolean): void;
getCurrentRouteSegment(): Promise<RouteSegment>;
Expand Down
13 changes: 9 additions & 4 deletions src/navigation/navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type { LatLng, Location } from '../../shared/types';
import type {
AlternateRoutingStrategy,
AudioGuidance,
AudioGuidanceSettings,
RouteSegment,
RouteStatus,
RoutingStrategy,
Expand Down Expand Up @@ -504,12 +505,16 @@ export interface NavigationController {
setSpeedAlertOptions(speed: SpeedAlertOptions | null): void;

/**
* Sets the audio guidance type according to the provided index.
* @deprecated Use setAudioGuidanceSettings instead.
*/
setAudioGuidanceType(index: AudioGuidance): Promise<void>;

/**
* Sets the voice guidance mode, vibration, and Bluetooth-audio behavior.
*
* @param index - The index representing the desired audio
* guidance type.
* @param settings - The audio guidance settings to apply on Android and iOS.
*/
setAudioGuidanceType(index: AudioGuidance): void;
setAudioGuidanceSettings(settings: AudioGuidanceSettings): Promise<void>;

/**
* Disables location updates by the library. This should be
Expand Down
26 changes: 23 additions & 3 deletions src/navigation/navigation/useNavigationController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ import {
import type {
Waypoint,
AudioGuidance,
AudioGuidanceSettings,
RouteSegment,
TimeAndDistance,
RouteStatus,
} from '../types';
import { NavigationSessionStatus } from '../types';
import { AudioGuidanceMode, NavigationSessionStatus } from '../types';
import {
TaskRemovedBehavior,
type TurnByTurnEvent,
Expand All @@ -44,6 +45,20 @@ import {

const { NavModule } = NativeModules;

const validateAudioGuidanceSettings = (
settings: AudioGuidanceSettings
): void => {
if (
!settings ||
!Number.isInteger(settings.guidanceMode) ||
!Object.values(AudioGuidanceMode).includes(settings.guidanceMode) ||
typeof settings.vibrationEnabled !== 'boolean' ||
typeof settings.bluetoothAudioEnabled !== 'boolean'
) {
throw new Error('Invalid audio guidance settings.');
}
};

/**
* Individual listener setters type - maps each callback key to a setter function.
*/
Expand Down Expand Up @@ -485,8 +500,13 @@ export const useNavigationController = (
return NavModule.setAbnormalTerminatingReportingEnabled(enabled);
},

setAudioGuidanceType: (index: AudioGuidance) => {
NavModule.setAudioGuidanceType(index);
setAudioGuidanceType: async (index: AudioGuidance) => {
return await NavModule.setAudioGuidanceType(index);
},

setAudioGuidanceSettings: async (settings: AudioGuidanceSettings) => {
validateAudioGuidanceSettings(settings);
return await NavModule.setAudioGuidanceSettings(settings);
},

setBackgroundLocationUpdatesEnabled: (isEnabled: boolean) => {
Expand Down
28 changes: 26 additions & 2 deletions src/navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ export enum Status {
}

/**
* AudioGuidance is a set of flags used to specify what kinds of audio alerts and guidance are
* used during navigation.
* @deprecated Use AudioGuidanceSettings with setAudioGuidanceSettings instead.
* This legacy enum is retained for setAudioGuidanceType compatibility only.
*/
export enum AudioGuidance {
/**
Expand Down Expand Up @@ -164,6 +164,30 @@ export enum AudioGuidance {
VOICE_ALERTS_ONLY = 2,
}

/**
* The voice guidance mode used during navigation.
*/
export enum AudioGuidanceMode {
/** Disables voice guidance. */
SILENT = 0,
/** Enables voice guidance for alerts only. */
VOICE_ALERTS_ONLY,
/** Enables voice guidance for alerts and turn-by-turn instructions. */
VOICE_ALERTS_AND_GUIDANCE,
}

/**
* Settings for audio guidance during navigation on Android and iOS.
*/
export interface AudioGuidanceSettings {
/** The voice guidance mode. */
guidanceMode: AudioGuidanceMode;
/** Whether the device vibrates when voice alerts are played. */
vibrationEnabled: boolean;
/** Whether voice guidance uses Bluetooth when it is available. */
bluetoothAudioEnabled: boolean;
}

/**
* Defines an individual road stretch within a route polyline, and its rendering style based on
* traffic conditions. This is a NavSDK equivalent of the Google Maps RoadStretch.
Expand Down
Loading