Dactyloidae/mobile/ios/Client/Telemetry/UnifiedTelemetry.swift
2026-06-26 21:04:09 -07:00

119 lines
5.8 KiB
Swift

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import Shared
import Telemetry
//
// 'Unified Telemetry' is the name for Mozilla's telemetry system
//
class UnifiedTelemetry {
init(profile: Profile) {
NotificationCenter.default.addObserver(self, selector: #selector(uploadError(notification:)), name: Telemetry.notificationReportError, object: nil)
let telemetryConfig = Telemetry.default.configuration
telemetryConfig.appName = "Fennec"
telemetryConfig.userDefaultsSuiteName = AppInfo.sharedContainerIdentifier
telemetryConfig.dataDirectory = .documentDirectory
telemetryConfig.updateChannel = AppConstants.BuildChannel.rawValue
let sendUsageData = profile.prefs.boolForKey(AppConstants.PrefSendUsageData) ?? true
telemetryConfig.isCollectionEnabled = sendUsageData
telemetryConfig.isUploadEnabled = sendUsageData
telemetryConfig.measureUserDefaultsSetting(forKey: "profile.blockPopups", withDefaultValue: true)
telemetryConfig.measureUserDefaultsSetting(forKey: "profile.saveLogins", withDefaultValue: true)
telemetryConfig.measureUserDefaultsSetting(forKey: "profile.showClipboardBar", withDefaultValue: false)
telemetryConfig.measureUserDefaultsSetting(forKey: "profile.settings.closePrivateTabs", withDefaultValue: false)
telemetryConfig.measureUserDefaultsSetting(forKey: "profile.ASPocketStoriesVisible", withDefaultValue: true)
telemetryConfig.measureUserDefaultsSetting(forKey: "profile.ASBookmarkHighlightsVisible", withDefaultValue: true)
telemetryConfig.measureUserDefaultsSetting(forKey: "profile.ASRecentHighlightsVisible", withDefaultValue: true)
telemetryConfig.measureUserDefaultsSetting(forKey: "profile.prefkey.trackingprotection.enabled", withDefaultValue: "onInPrivateBrowsing")
telemetryConfig.measureUserDefaultsSetting(forKey: "profile.prefkey.trackingprotection.strength", withDefaultValue: "basic")
let prefs = profile.prefs
Telemetry.default.beforeSerializePing(pingType: CorePingBuilder.PingType) { (inputDict) -> [String: Any?] in
var outputDict = inputDict // make a mutable copy
if let newTabChoice = prefs.stringForKey(NewTabAccessors.PrefKey) {
outputDict["defaultNewTabExperience"] = newTabChoice as AnyObject?
}
if let chosenEmailClient = prefs.stringForKey(PrefsKeys.KeyMailToOption) {
outputDict["defaultMailClient"] = chosenEmailClient as AnyObject?
}
return outputDict
}
Telemetry.default.beforeSerializePing(pingType: MobileEventPingBuilder.PingType) { (inputDict) -> [String : Any?] in
var outputDict = inputDict
var settings: [String : Any?] = inputDict["settings"] as? [String : Any?] ?? [:]
let searchEngines = SearchEngines(prefs: profile.prefs, files: profile.files)
settings["defaultSearchEngine"] = searchEngines.defaultEngine.engineID ?? "custom"
outputDict["settings"] = settings
return outputDict
}
Telemetry.default.add(pingBuilderType: CorePingBuilder.self)
Telemetry.default.add(pingBuilderType: MobileEventPingBuilder.self)
}
@objc func uploadError(notification: NSNotification) {
guard !DeviceInfo.isSimulator(), let error = notification.userInfo?["error"] as? NSError else { return }
Sentry.shared.send(message: "Upload Error", tag: SentryTag.unifiedTelemetry, severity: .info, description: error.debugDescription)
}
}
// Enums for Event telemetry.
extension UnifiedTelemetry {
public enum EventCategory: String {
case action = "action"
}
public enum EventMethod: String {
case add = "add"
case background = "background"
case change = "change"
case delete = "delete"
case foreground = "foreground"
case open = "open"
case scan = "scan"
case tap = "tap"
case view = "view"
}
public enum EventObject: String {
case app = "app"
case bookmark = "bookmark"
case bookmarksPanel = "bookmarks-panel"
case qrCodeText = "qr-code-text"
case qrCodeURL = "qr-code-url"
case readerModeCloseButton = "reader-mode-close-button"
case readerModeOpenButton = "reader-mode-open-button"
case readingListItem = "reading-list-item"
case setting = "setting"
}
public enum EventValue: String {
case activityStream = "activity-stream"
case appMenu = "app-menu"
case awesomebarResults = "awesomebar-results"
case bookmarksPanel = "bookmarks-panel"
case homePanelTabButton = "home-panel-tab-button"
case markAsRead = "mark-as-read"
case markAsUnread = "mark-as-unread"
case pageActionMenu = "page-action-menu"
case readerModeToolbar = "reader-mode-toolbar"
case readingListPanel = "reading-list-panel"
case shareExtension = "share-extension"
case shareMenu = "share-menu"
}
public static func recordEvent(category: EventCategory, method: EventMethod, object: EventObject, value: EventValue, extras: [String : Any?]? = nil) {
Telemetry.default.recordEvent(category: category.rawValue, method: method.rawValue, object: object.rawValue, value: value.rawValue, extras: extras)
}
public static func recordEvent(category: EventCategory, method: EventMethod, object: EventObject, value: String? = nil, extras: [String : Any?]? = nil) {
Telemetry.default.recordEvent(category: category.rawValue, method: method.rawValue, object: object.rawValue, value: value, extras: extras)
}
}