2021-10-27 13:51:46 +00:00
|
|
|
//
|
|
|
|
// Copyright 2021 New Vector Ltd
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
|
|
|
|
|
|
|
import PostHog
|
2021-11-24 18:04:54 +00:00
|
|
|
import AnalyticsEvents
|
2021-10-27 13:51:46 +00:00
|
|
|
|
|
|
|
@objcMembers class Analytics: NSObject {
|
|
|
|
|
|
|
|
// MARK: - Properties
|
|
|
|
|
|
|
|
static let shared = Analytics()
|
|
|
|
|
|
|
|
private var postHog: PHGPostHog?
|
|
|
|
|
2021-11-22 14:28:09 +00:00
|
|
|
var isRunning: Bool { postHog?.enabled ?? false }
|
2021-10-27 13:51:46 +00:00
|
|
|
|
2021-11-19 10:00:24 +00:00
|
|
|
var shouldShowAnalyticsPrompt: Bool {
|
|
|
|
// Show an analytics prompt when the user hasn't seen the PostHog prompt before
|
|
|
|
// so long as they haven't previously declined the Matomo analytics prompt.
|
|
|
|
!RiotSettings.shared.hasSeenAnalyticsPrompt && !RiotSettings.shared.hasDeclinedMatomoAnalytics
|
2021-10-27 13:51:46 +00:00
|
|
|
}
|
|
|
|
|
2021-11-19 10:00:24 +00:00
|
|
|
var promptShouldDisplayUpgradeMessage: Bool {
|
|
|
|
// Show an analytics prompt when the user hasn't seen the PostHog prompt before
|
|
|
|
// so long as they haven't previously declined the Matomo analytics prompt.
|
|
|
|
RiotSettings.shared.hasAcceptedMatomoAnalytics
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Public
|
|
|
|
|
2021-10-27 13:51:46 +00:00
|
|
|
func optIn(with session: MXSession?) {
|
|
|
|
guard let session = session else { return }
|
2021-11-19 10:00:24 +00:00
|
|
|
RiotSettings.shared.enableAnalytics = true
|
2021-10-27 13:51:46 +00:00
|
|
|
|
|
|
|
var settings = AnalyticsSettings(session: session)
|
|
|
|
|
2021-11-19 10:00:24 +00:00
|
|
|
if settings.id == nil {
|
|
|
|
settings.generateID()
|
|
|
|
|
|
|
|
session.setAccountData(settings.dictionary, forType: AnalyticsSettings.eventType) {
|
|
|
|
MXLog.debug("[Analytics] Successfully updated analytics settings in account data.")
|
|
|
|
} failure: { error in
|
|
|
|
MXLog.error("[Analytics] Failed to update analytics settings.")
|
|
|
|
}
|
2021-10-27 13:51:46 +00:00
|
|
|
}
|
|
|
|
|
2021-11-19 10:00:24 +00:00
|
|
|
startIfEnabled()
|
|
|
|
|
|
|
|
if !RiotSettings.shared.isIdentifiedForAnalytics {
|
|
|
|
identify(with: settings)
|
2021-10-27 13:51:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-19 10:00:24 +00:00
|
|
|
func optOut() {
|
|
|
|
RiotSettings.shared.enableAnalytics = false
|
|
|
|
reset()
|
|
|
|
}
|
|
|
|
|
|
|
|
func startIfEnabled() {
|
|
|
|
guard RiotSettings.shared.enableAnalytics, !isRunning else { return }
|
2021-10-27 13:51:46 +00:00
|
|
|
|
2021-11-24 11:07:34 +00:00
|
|
|
// Ensures that analytics are configured BuildSettings
|
|
|
|
guard let configuration = PHGPostHogConfiguration.standard else { return }
|
|
|
|
|
|
|
|
postHog = PHGPostHog(configuration: configuration)
|
2021-10-27 13:51:46 +00:00
|
|
|
postHog?.enable()
|
|
|
|
MXLog.debug("[Analytics] Started.")
|
2021-11-19 16:32:39 +00:00
|
|
|
|
|
|
|
// Catch and log crashes
|
|
|
|
MXLogger.logCrashes(true)
|
|
|
|
MXLogger.setBuildVersion(AppDelegate.theDelegate().build)
|
2021-11-19 10:00:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private func identify(with settings: AnalyticsSettings) {
|
|
|
|
guard let id = settings.id else {
|
|
|
|
MXLog.warning("[Analytics] identify(with:) called before an ID has been generated.")
|
|
|
|
return
|
2021-10-27 13:51:46 +00:00
|
|
|
}
|
|
|
|
|
2021-11-19 10:00:24 +00:00
|
|
|
postHog?.identify(id)
|
|
|
|
MXLog.debug("[Analytics] Identified.")
|
|
|
|
RiotSettings.shared.isIdentifiedForAnalytics = true
|
2021-10-27 13:51:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func reset() {
|
|
|
|
guard isRunning else { return }
|
|
|
|
|
|
|
|
postHog?.disable()
|
|
|
|
MXLog.debug("[Analytics] Stopped.")
|
|
|
|
|
|
|
|
postHog?.reset()
|
2021-11-19 10:00:24 +00:00
|
|
|
RiotSettings.shared.isIdentifiedForAnalytics = false
|
2021-10-27 13:51:46 +00:00
|
|
|
|
|
|
|
postHog = nil
|
2021-11-19 16:32:39 +00:00
|
|
|
|
|
|
|
MXLogger.logCrashes(false)
|
2021-10-27 13:51:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func forceUpload() {
|
|
|
|
postHog?.flush()
|
|
|
|
}
|
|
|
|
|
2021-11-30 12:54:29 +00:00
|
|
|
private func capture(event: AnalyticsEventProtocol) {
|
|
|
|
postHog?.capture(event.eventName, properties: event.properties)
|
2021-10-27 13:51:46 +00:00
|
|
|
}
|
2021-11-24 10:43:22 +00:00
|
|
|
|
2021-11-24 18:04:54 +00:00
|
|
|
func trackScreen(_ screen: AnalyticsScreen) {
|
2021-11-30 12:54:29 +00:00
|
|
|
let event = AnalyticsEvent.Screen(durationMs: nil, screenName: screen.screenName)
|
|
|
|
postHog?.screen(event.screenName.rawValue, properties: event.properties)
|
2021-10-27 13:51:46 +00:00
|
|
|
}
|
2021-11-24 10:43:22 +00:00
|
|
|
|
|
|
|
func trackE2EEError(_ reason: DecryptionFailureReason, count: Int) {
|
|
|
|
for _ in 0..<count {
|
2021-11-30 12:54:29 +00:00
|
|
|
let event = AnalyticsEvent.Error(context: nil, domain: .E2EE, name: reason.errorName)
|
|
|
|
capture(event: event)
|
2021-11-24 10:43:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func trackIdentityServerAccepted(granted: Bool) {
|
|
|
|
// Do we still want to track this?
|
|
|
|
}
|
2021-10-27 13:51:46 +00:00
|
|
|
}
|
|
|
|
|
2021-11-24 10:43:22 +00:00
|
|
|
// MARK: - MXAnalyticsDelegate
|
2021-10-27 13:51:46 +00:00
|
|
|
extension Analytics: MXAnalyticsDelegate {
|
2021-11-30 12:54:29 +00:00
|
|
|
func trackDuration(_ seconds: TimeInterval, category: MXTaskProfileCategory, name: MXTaskProfileName) {
|
|
|
|
if let analyticsName = name.analyticsName {
|
|
|
|
let event = AnalyticsEvent.PerformanceTimer(context: nil, name: analyticsName, timeMs: Int(seconds * 1000))
|
|
|
|
capture(event: event)
|
|
|
|
} else {
|
|
|
|
MXLog.warning("[Analytics] Attempt to capture unknown profile task: \(category.rawValue) - \(name.rawValue)")
|
|
|
|
}
|
|
|
|
}
|
2021-11-24 10:43:22 +00:00
|
|
|
|
2021-11-25 18:28:32 +00:00
|
|
|
func trackCallStarted(withVideo isVideo: Bool, numberOfParticipants: Int, incoming isIncoming: Bool) {
|
2021-11-30 12:54:29 +00:00
|
|
|
let event = AnalyticsEvent.CallStarted(isVideo: isVideo, numParticipants: numberOfParticipants, placed: !isIncoming)
|
|
|
|
capture(event: event)
|
2021-11-24 10:43:22 +00:00
|
|
|
}
|
|
|
|
|
2021-11-25 18:28:32 +00:00
|
|
|
func trackCallEnded(withDuration duration: Int, video isVideo: Bool, numberOfParticipants: Int, incoming isIncoming: Bool) {
|
2021-11-30 12:54:29 +00:00
|
|
|
let event = AnalyticsEvent.CallEnded(durationMs: duration, isVideo: isVideo, numParticipants: numberOfParticipants, placed: !isIncoming)
|
|
|
|
capture(event: event)
|
2021-11-24 10:43:22 +00:00
|
|
|
}
|
|
|
|
|
2021-11-25 18:28:32 +00:00
|
|
|
func trackCallError(with reason: __MXCallHangupReason, video isVideo: Bool, numberOfParticipants: Int, incoming isIncoming: Bool) {
|
2021-11-30 12:54:29 +00:00
|
|
|
let callEvent = AnalyticsEvent.CallError(isVideo: isVideo, numParticipants: numberOfParticipants, placed: !isIncoming)
|
|
|
|
let event = AnalyticsEvent.Error(context: nil, domain: .VOIP, name: reason.errorName)
|
|
|
|
capture(event: callEvent)
|
|
|
|
capture(event: event)
|
2021-10-27 13:51:46 +00:00
|
|
|
}
|
|
|
|
|
2021-11-24 10:43:22 +00:00
|
|
|
func trackContactsAccessGranted(_ granted: Bool) {
|
|
|
|
// Do we still want to track this?
|
2021-10-27 13:51:46 +00:00
|
|
|
}
|
|
|
|
}
|