Skip to content

Commit f6cf288

Browse files
authored
Add support of Native Telemetry by flag (#4349)
1 parent ab6e59e commit f6cf288

File tree

44 files changed

+2951
-496
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2951
-496
lines changed

MapboxNavigation.xcodeproj/project.pbxproj

Lines changed: 121 additions & 5 deletions
Large diffs are not rendered by default.

Package.resolved

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/MapboxCoreNavigation/CoreNavigationNavigator.swift

Lines changed: 82 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,33 @@
11
import MapboxNavigationNative
22
import MapboxDirections
33
@_implementationOnly import MapboxCommon_Private
4+
@_implementationOnly import MapboxNavigationNative_Private
5+
6+
enum RouteChangeReason {
7+
/// Clean a route.
8+
case cleanUp
9+
10+
/// Set a new route, use by default.
11+
case startNewRoute
12+
13+
/// Route index changed to an alternative.
14+
case switchToAlternative
15+
16+
/// New route from different starting point to previous destinations.
17+
case reroute
18+
19+
/// Recreate Navigator after losing internet connection.
20+
case fallbackToOffline
21+
22+
/// Recreate Navigator after restoring internet connection.
23+
case restoreToOnline
24+
25+
/// Navigator used offline route and new route is available from the server.
26+
case switchToOnline
27+
28+
/// Fastest Route available (and should be switched),
29+
case fastestRouteAvailable
30+
}
431

532
protocol CoreNavigator {
633
static var shared: Self { get }
@@ -22,6 +49,7 @@ protocol CoreNavigator {
2249
func setRoutes(_ routesData: RoutesData,
2350
uuid: UUID,
2451
legIndex: UInt32,
52+
reason: RouteChangeReason,
2553
completion: @escaping (Result<RoutesCoordinator.RoutesResult, Error>) -> Void)
2654
func setAlternativeRoutes(with routes: [RouteInterface],
2755
completion: @escaping (Result<[RouteAlternative], Error>) -> Void)
@@ -30,6 +58,10 @@ protocol CoreNavigator {
3058

3159
func updateLocation(_ location: CLLocation, completion: @escaping (Bool) -> Void)
3260

61+
func makeTelemetry(eventsMetadataProvider: EventsMetadataInterface) -> Telemetry
62+
63+
func makeEventsMetadataProvider() -> EventsMetadataProvider
64+
3365
func resume()
3466
func pause()
3567
}
@@ -62,14 +94,13 @@ final class Navigator: CoreNavigator {
6294
}
6395

6496
private lazy var routeCoordinator: RoutesCoordinator = {
65-
.init(routesSetupHandler: { [weak self] routesData, legIndex, completion in
97+
.init(routesSetupHandler: { [weak self] routesData, legIndex, reason, completion in
6698

6799
let dataParams = routesData.map { SetRoutesDataParams(routes: $0,
68100
legIndex: legIndex) }
69-
70-
let reason: SetRoutesReason = routesData != nil ? .newRoute : .cleanUp
101+
71102
self?.navigator.setRoutesDataFor(dataParams,
72-
reason: reason) { [weak self] result in
103+
reason: reason.navNativeValue) { [weak self] result in
73104
if result.isValue(),
74105
let routesResult = result.value {
75106
Log.info("Navigator has been updated, including \(routesResult.alternatives.count) alternatives.", category: .navigation)
@@ -146,10 +177,12 @@ final class Navigator: CoreNavigator {
146177
cacheHandle = factory.cacheHandle
147178
roadGraph = factory.roadGraph
148179
navigator = factory.navigator
180+
149181
roadObjectStore = RoadObjectStore(navigator.roadObjectStore())
150182
roadObjectMatcher = RoadObjectMatcher(MapboxNavigationNative.RoadObjectMatcher(cache: cacheHandle))
151183
rerouteController = RerouteController(navigator, config: NativeHandlersFactory.configHandle())
152-
184+
eventAppState = EventAppState()
185+
153186
subscribeNavigator()
154187
setupAlternativesControllerIfNeeded()
155188
}
@@ -174,14 +207,22 @@ final class Navigator: CoreNavigator {
174207
cacheHandle = factory.cacheHandle
175208
roadGraph = factory.roadGraph
176209
navigator = factory.navigator
177-
210+
178211
roadObjectStore.native = navigator.roadObjectStore()
179212
roadObjectMatcher.native = MapboxNavigationNative.RoadObjectMatcher(cache: cacheHandle)
180213
rerouteController = RerouteController(navigator, config: NativeHandlersFactory.configHandle())
181214

182215
subscribeNavigator()
183216
setupAlternativesControllerIfNeeded()
184217
}
218+
219+
func makeTelemetry(eventsMetadataProvider: EventsMetadataInterface) -> Telemetry {
220+
navigator.getTelemetryForEventsMetadataProvider(eventsMetadataProvider)
221+
}
222+
223+
func makeEventsMetadataProvider() -> EventsMetadataProvider {
224+
EventsMetadataProvider(appState: eventAppState)
225+
}
185226

186227
private weak var navigatorStatusObserver: NavigatorStatusObserver?
187228
private weak var navigatorFallbackVersionsObserver: NavigatorFallbackVersionsObserver?
@@ -257,6 +298,8 @@ final class Navigator: CoreNavigator {
257298
private(set) var roadObjectMatcher: RoadObjectMatcher
258299

259300
private var isSubscribedToElectronicHorizon = false
301+
302+
private var eventAppState: EventAppState
260303

261304
private var electronicHorizonOptions: ElectronicHorizonOptions? {
262305
didSet {
@@ -282,8 +325,16 @@ final class Navigator: CoreNavigator {
282325

283326
// MARK: - Navigator Updates
284327

285-
func setRoutes(_ routesData: RoutesData, uuid: UUID, legIndex: UInt32, completion: @escaping (Result<RoutesCoordinator.RoutesResult, Error>) -> Void) {
286-
routeCoordinator.beginActiveNavigation(with: routesData, uuid: uuid, legIndex: legIndex, completion: completion)
328+
func setRoutes(_ routesData: RoutesData,
329+
uuid: UUID,
330+
legIndex: UInt32,
331+
reason: RouteChangeReason,
332+
completion: @escaping (Result<RoutesCoordinator.RoutesResult, Error>) -> Void) {
333+
routeCoordinator.beginActiveNavigation(with: routesData,
334+
uuid: uuid,
335+
legIndex: legIndex,
336+
reason: reason,
337+
completion: completion)
287338
}
288339

289340
func setAlternativeRoutes(with routes: [RouteInterface], completion: @escaping (Result<[RouteAlternative], Error>) -> Void) {
@@ -459,3 +510,26 @@ enum NavigatorError: Swift.Error {
459510
case failedToUpdateRoutes(reason: String)
460511
case failedToUpdateAlternativeRoutes(reason: String)
461512
}
513+
514+
extension RouteChangeReason {
515+
var navNativeValue: SetRoutesReason {
516+
switch self {
517+
case .cleanUp:
518+
return .cleanUp
519+
case .startNewRoute:
520+
return .newRoute
521+
case .switchToAlternative:
522+
return .alternative
523+
case .reroute:
524+
return .reroute
525+
case .fallbackToOffline:
526+
return .fallbackToOffline
527+
case .restoreToOnline:
528+
return .restoreToOnline
529+
case .switchToOnline:
530+
return .switchToOnline
531+
case .fastestRouteAvailable:
532+
return .fastestRoute
533+
}
534+
}
535+
}

Sources/MapboxCoreNavigation/Feedback/FeedbackEvent.swift

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,38 @@ import Foundation
66
Conforms to the `Codable` protocol, so the application can store the event persistently.
77
*/
88
public class FeedbackEvent: Codable {
9+
let contentType: FeedbackContent
10+
11+
enum FeedbackContent: Codable {
12+
case common(FeedbackCommonEvent)
13+
case native(FeedbackMetadata)
14+
}
15+
16+
convenience init(eventDetails: NavigationEventDetails) {
17+
self.init(contentType: .common(FeedbackCommonEvent(eventDetails: eventDetails)))
18+
}
19+
20+
convenience init(metadata: FeedbackMetadata) {
21+
self.init(contentType: .native(metadata))
22+
}
23+
24+
init(contentType: FeedbackContent) {
25+
self.contentType = contentType
26+
}
27+
28+
/// :nodoc:
29+
public var contents: [String: Any] {
30+
switch contentType {
31+
case .common(let data):
32+
return data.contents
33+
case .native(let data):
34+
return data.contents
35+
}
36+
}
37+
}
38+
39+
// To be removed after only NN Telemetry is used
40+
class FeedbackCommonEvent: Codable {
941
let coreEvent: CoreFeedbackEvent
1042

1143
init(eventDetails: NavigationEventDetails) {
@@ -34,8 +66,7 @@ public class FeedbackEvent: Codable {
3466
coreEvent.eventDictionary["description"] = description
3567
}
3668

37-
/// :nodoc:
38-
public var contents: [String: Any] {
69+
var contents: [String: Any] {
3970
coreEvent.eventDictionary
4071
}
4172
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import Foundation
2+
import CoreLocation
3+
import MapboxNavigationNative
4+
@_implementationOnly import MapboxNavigationNative_Private
5+
6+
/// :nodoc:
7+
@_spi(MapboxInternal)
8+
public struct FeedbackMetadata {
9+
private let userFeedbackHandle: NativeUserFeedbackHandle?
10+
private var calculatedUserFeedbackMetadata: UserFeedbackMetadata? = nil
11+
12+
var userFeedbackMetadata: UserFeedbackMetadata? {
13+
calculatedUserFeedbackMetadata ?? userFeedbackHandle?.getMetadata()
14+
}
15+
16+
public let screenshot: String?
17+
public var contents: [String: Any] {
18+
guard let data = try? JSONEncoder().encode(self),
19+
let dictionary = try? JSONSerialization.jsonObject(
20+
with: data, options: .allowFragments) as? [String: Any] else {
21+
Log.warning("Unable to encode feedback event details", category: .navigation)
22+
return [:]
23+
}
24+
return dictionary
25+
}
26+
27+
init(userFeedbackHandle: NativeUserFeedbackHandle?,
28+
screenshot: String?,
29+
userFeedbackMetadata: UserFeedbackMetadata? = nil) {
30+
self.userFeedbackHandle = userFeedbackHandle
31+
self.screenshot = screenshot
32+
self.calculatedUserFeedbackMetadata = userFeedbackMetadata
33+
}
34+
}
35+
36+
extension FeedbackMetadata: Codable {
37+
fileprivate enum CodingKeys: String, CodingKey {
38+
case screenshot
39+
case locationsBefore
40+
case locationsAfter
41+
case step
42+
}
43+
44+
public init(from decoder: Decoder) throws {
45+
let container = try decoder.container(keyedBy: CodingKeys.self)
46+
screenshot = try container.decodeIfPresent(String.self, forKey: .screenshot)
47+
calculatedUserFeedbackMetadata = try? UserFeedbackMetadata(from: decoder)
48+
userFeedbackHandle = nil
49+
}
50+
51+
public func encode(to encoder: Encoder) throws {
52+
var container = encoder.container(keyedBy: CodingKeys.self)
53+
try container.encodeIfPresent(screenshot, forKey: .screenshot)
54+
try userFeedbackMetadata?.encode(to: encoder)
55+
}
56+
}
57+
58+
/// :nodoc:
59+
@_spi(MapboxInternal)
60+
extension UserFeedbackMetadata: Encodable {
61+
public func encode(to encoder: Encoder) throws {
62+
var container = encoder.container(keyedBy: FeedbackMetadata.CodingKeys.self)
63+
let eventLocationsAfter: [EventFixLocation] = locationsAfter.map { .init($0) }
64+
let eventLocationsBefore: [EventFixLocation] = locationsBefore.map { .init($0) }
65+
let eventStep = step.map { EventStep($0) }
66+
try container.encode(eventLocationsAfter, forKey: .locationsAfter)
67+
try container.encode(eventLocationsBefore, forKey: .locationsBefore)
68+
try container.encodeIfPresent(eventStep, forKey: .step)
69+
}
70+
71+
convenience init(from decoder: Decoder) throws {
72+
let container = try decoder.container(keyedBy: FeedbackMetadata.CodingKeys.self)
73+
let locationsBefore = try container.decode([EventFixLocation].self, forKey: .locationsBefore)
74+
let locationsAfter = try container.decode([EventFixLocation].self, forKey: .locationsAfter)
75+
let eventStep = try container.decodeIfPresent(EventStep.self, forKey: .step)
76+
77+
self.init(locationsBefore: locationsBefore.map { FixLocation($0) },
78+
locationsAfter: locationsAfter.map { FixLocation($0) },
79+
step: Step(eventStep))
80+
}
81+
}

Sources/MapboxCoreNavigation/NativeHandlersFactory.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,12 @@ class NativeHandlersFactory {
134134
}
135135

136136
static func configHandle(by configFactoryType: ConfigFactory.Type = ConfigFactory.self) -> ConfigHandle {
137+
var features = ["useInternalReroute": true]
138+
if NavigationTelemetryConfiguration.useNavNativeTelemetryEvents {
139+
features["useTelemetryNavigationEvents"] = true
140+
}
137141
let defaultConfig = [
138-
customConfigFeaturesKey: [
139-
"useInternalReroute": true
140-
]
142+
customConfigFeaturesKey: features
141143
]
142144

143145
var customConfig = UserDefaults.standard.dictionary(forKey: customConfigKey) ?? [:]

0 commit comments

Comments
 (0)