Skip to content

RUM-10378 Collect battery attributes #2351

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
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
18 changes: 18 additions & 0 deletions Datadog/Datadog.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -850,12 +850,18 @@
86092FDE2DEDC6830075D63B /* AccessibilityValuesMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86092FDC2DEDC6830075D63B /* AccessibilityValuesMock.swift */; };
862B0B272DEF2D8000F61E73 /* MockNotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 862B0B262DEF2D8000F61E73 /* MockNotificationCenter.swift */; };
862B0B282DEF2D8000F61E73 /* MockNotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 862B0B262DEF2D8000F61E73 /* MockNotificationCenter.swift */; };
8648D0782E01A389002F226B /* BrightnessLevelPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8648D0772E01A389002F226B /* BrightnessLevelPublisher.swift */; };
8648D0792E01A389002F226B /* BrightnessLevelPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8648D0772E01A389002F226B /* BrightnessLevelPublisher.swift */; };
8648D07B2E01ABB0002F226B /* BrightnessLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8648D07A2E01ABB0002F226B /* BrightnessLevel.swift */; };
8648D07C2E01ABB0002F226B /* BrightnessLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8648D07A2E01ABB0002F226B /* BrightnessLevel.swift */; };
864A70792DDF742A00AC0619 /* Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864A70782DDF742A00AC0619 /* Accessibility.swift */; };
864A707A2DDF742A00AC0619 /* Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864A70782DDF742A00AC0619 /* Accessibility.swift */; };
864A707C2DDF743900AC0619 /* AccessibilityReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864A707B2DDF743900AC0619 /* AccessibilityReader.swift */; };
864A707D2DDF743900AC0619 /* AccessibilityReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864A707B2DDF743900AC0619 /* AccessibilityReader.swift */; };
864A70802DE092AD00AC0619 /* AccessibilityReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864A707E2DE092AD00AC0619 /* AccessibilityReaderTests.swift */; };
864A70812DE092AD00AC0619 /* AccessibilityReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864A707E2DE092AD00AC0619 /* AccessibilityReaderTests.swift */; };
866CA4A82E02EE0100E0CD03 /* BrightnessLevelPublisherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 866CA4A72E02EE0100E0CD03 /* BrightnessLevelPublisherTests.swift */; };
866CA4A92E02EE0100E0CD03 /* BrightnessLevelPublisherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 866CA4A72E02EE0100E0CD03 /* BrightnessLevelPublisherTests.swift */; };
960A0D3B2D6E2490004BB999 /* Reflector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 960A0D3A2D6E2490004BB999 /* Reflector.swift */; };
960A0D3C2D6E2490004BB999 /* CustomDump.swift in Sources */ = {isa = PBXBuildFile; fileRef = 960A0D382D6E2490004BB999 /* CustomDump.swift */; };
960A0D3D2D6E2490004BB999 /* ReflectionMirror.swift in Sources */ = {isa = PBXBuildFile; fileRef = 960A0D392D6E2490004BB999 /* ReflectionMirror.swift */; };
Expand Down Expand Up @@ -2954,9 +2960,12 @@
61FF9A4425AC5DEA001058CC /* ViewIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewIdentifier.swift; sourceTree = "<group>"; };
86092FDC2DEDC6830075D63B /* AccessibilityValuesMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityValuesMock.swift; sourceTree = "<group>"; };
862B0B262DEF2D8000F61E73 /* MockNotificationCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockNotificationCenter.swift; sourceTree = "<group>"; };
8648D0772E01A389002F226B /* BrightnessLevelPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrightnessLevelPublisher.swift; sourceTree = "<group>"; };
8648D07A2E01ABB0002F226B /* BrightnessLevel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrightnessLevel.swift; sourceTree = "<group>"; };
864A70782DDF742A00AC0619 /* Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Accessibility.swift; sourceTree = "<group>"; };
864A707B2DDF743900AC0619 /* AccessibilityReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityReader.swift; sourceTree = "<group>"; };
864A707E2DE092AD00AC0619 /* AccessibilityReaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityReaderTests.swift; sourceTree = "<group>"; };
866CA4A72E02EE0100E0CD03 /* BrightnessLevelPublisherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrightnessLevelPublisherTests.swift; sourceTree = "<group>"; };
960A0D382D6E2490004BB999 /* CustomDump.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDump.swift; sourceTree = "<group>"; };
960A0D392D6E2490004BB999 /* ReflectionMirror.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReflectionMirror.swift; sourceTree = "<group>"; };
960A0D3A2D6E2490004BB999 /* Reflector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reflector.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -5438,6 +5447,7 @@
D26C49AE2886DC7B00802B2D /* ApplicationStatePublisherTests.swift */,
D2C7E3AA28F97DCF0023B2CC /* BatteryStatusPublisherTests.swift */,
D234613028B7712F00055D4C /* FeatureContextTests.swift */,
866CA4A72E02EE0100E0CD03 /* BrightnessLevelPublisherTests.swift */,
);
path = Context;
sourceTree = "<group>";
Expand Down Expand Up @@ -6232,6 +6242,7 @@
D23039BE298D5235001A1FA3 /* LaunchTime.swift */,
D2F8235229915E12003C7E99 /* DatadogSite.swift */,
6174D6122BFDF16C00EC7469 /* BundleType.swift */,
8648D07A2E01ABB0002F226B /* BrightnessLevel.swift */,
);
path = Context;
sourceTree = "<group>";
Expand Down Expand Up @@ -6793,6 +6804,7 @@
D2EFA867286DA85700F1FAA6 /* DatadogContextProvider.swift */,
D20605A2287464F40047275C /* ContextValuePublisher.swift */,
D20605A5287476230047275C /* ServerOffsetPublisher.swift */,
8648D0772E01A389002F226B /* BrightnessLevelPublisher.swift */,
D20605A82874C1CD0047275C /* NetworkConnectionInfoPublisher.swift */,
D20605B12874E1660047275C /* CarrierInfoPublisher.swift */,
D2A1EE31287DA51900D28DFB /* UserInfoPublisher.swift */,
Expand Down Expand Up @@ -8376,6 +8388,7 @@
D26C49BF288982DA00802B2D /* FeatureUpload.swift in Sources */,
A70A82652A935F210072F5DC /* BackgroundTaskCoordinator.swift in Sources */,
61D3E0D2277B23F1008BE766 /* KronosInternetAddress.swift in Sources */,
8648D0782E01A389002F226B /* BrightnessLevelPublisher.swift in Sources */,
D2553826288F0B1A00727FAD /* BatteryStatusPublisher.swift in Sources */,
61D3E0D5277B23F1008BE766 /* KronosNTPPacket.swift in Sources */,
6128F5712BA223D100D35B08 /* DataStore+TLV.swift in Sources */,
Expand Down Expand Up @@ -8466,6 +8479,7 @@
61133C582423990D00786299 /* FileWriterTests.swift in Sources */,
D22743DC29DEB8B4001A7EF9 /* VitalRefreshRateReaderTests.swift in Sources */,
617B954224BF4E7600E6F443 /* RUMMonitorConfigurationTests.swift in Sources */,
866CA4A92E02EE0100E0CD03 /* BrightnessLevelPublisherTests.swift in Sources */,
3C0D5DE22A543DC400446CF9 /* EventGeneratorTests.swift in Sources */,
6136CB4A2A69C29C00AC265D /* FilesOrchestrator+MetricsTests.swift in Sources */,
266BFA5E2D6F4E31003041A5 /* AccountInfoPublisherTests.swift in Sources */,
Expand Down Expand Up @@ -8978,6 +8992,7 @@
D2303A01298D5236001A1FA3 /* DateFormatting.swift in Sources */,
D23039F1298D5236001A1FA3 /* AnyDecodable.swift in Sources */,
6167E6E22B81207200C3CA2D /* DDCrashReport.swift in Sources */,
8648D07B2E01ABB0002F226B /* BrightnessLevel.swift in Sources */,
D2160CC529C0DED100FAA9A5 /* URLSessionTaskInterception.swift in Sources */,
6167E6FD2B81EC0400C3CA2D /* BacktraceReporter.swift in Sources */,
D23039DD298D5235001A1FA3 /* DD.swift in Sources */,
Expand Down Expand Up @@ -9751,6 +9766,7 @@
D2612F48290197C700509B7D /* LaunchTimePublisher.swift in Sources */,
A70A82662A935F210072F5DC /* BackgroundTaskCoordinator.swift in Sources */,
D2A1EE24287740B500D28DFB /* ApplicationStatePublisher.swift in Sources */,
8648D0792E01A389002F226B /* BrightnessLevelPublisher.swift in Sources */,
D2CB6E2927C50EAE00A62B57 /* KronosInternetAddress.swift in Sources */,
6128F5722BA223D100D35B08 /* DataStore+TLV.swift in Sources */,
D2CB6E2C27C50EAE00A62B57 /* KronosNTPPacket.swift in Sources */,
Expand Down Expand Up @@ -9861,6 +9877,7 @@
D2CB6F1A27C520D400A62B57 /* FileReaderTests.swift in Sources */,
266BFA5F2D6F4E31003041A5 /* AccountInfoPublisherTests.swift in Sources */,
D2777D9E29F6A75800FFBB40 /* TelemetryReceiverTests.swift in Sources */,
866CA4A82E02EE0100E0CD03 /* BrightnessLevelPublisherTests.swift in Sources */,
D2A1EE39287EEB7600D28DFB /* NetworkConnectionInfoPublisherTests.swift in Sources */,
D2CB6F1D27C520D400A62B57 /* DataUploaderTests.swift in Sources */,
D2A1EE35287EB8DB00D28DFB /* ServerOffsetPublisherTests.swift in Sources */,
Expand Down Expand Up @@ -10083,6 +10100,7 @@
6167E6E32B81207200C3CA2D /* DDCrashReport.swift in Sources */,
D2160CC629C0DED100FAA9A5 /* URLSessionTaskInterception.swift in Sources */,
6167E6FE2B81EC0400C3CA2D /* BacktraceReporter.swift in Sources */,
8648D07C2E01ABB0002F226B /* BrightnessLevel.swift in Sources */,
D2DA2372298D57AA00C6C7E6 /* DD.swift in Sources */,
D2160C9B29C0DE5700FAA9A5 /* FirstPartyHosts.swift in Sources */,
D2EBEE3029BA161100B15732 /* TracePropagationHeadersReader.swift in Sources */,
Expand Down
55 changes: 55 additions & 0 deletions DatadogCore/Sources/Core/Context/BrightnessLevelPublisher.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2019-Present Datadog, Inc.
*/

import Foundation
import DatadogInternal

#if os(iOS)
import UIKit

/// A publisher that publishes the screen brightness level from UIScreen.
internal final class BrightnessLevelPublisher: ContextValuePublisher {
/// The initial brightness level.
let initialValue: BrightnessLevel?

/// The notification center to observe brightness changes.
private let notificationCenter: NotificationCenter
private let screen: UIScreen
private var observers: [Any]? = nil

init(notificationCenter: NotificationCenter = .default, screen: UIScreen = .main) {
self.notificationCenter = notificationCenter
self.screen = screen
self.initialValue = Float(screen.brightness)
}

/// Publishes the brightness level to the given receiver.
///
/// - Parameter receiver: The receiver to publish the brightness level to.
func publish(to receiver: @escaping ContextValueReceiver<BrightnessLevel?>) {
let block = { (notification: Notification) in
receiver(Float(self.screen.brightness))
}

observers = [
notificationCenter.addObserver(
forName: UIScreen.brightnessDidChangeNotification,
object: nil,
queue: .main,
using: block
)
]

receiver(initialValue)
}

func cancel() {
observers?.forEach(notificationCenter.removeObserver)
observers = nil
}
}

#endif
4 changes: 4 additions & 0 deletions DatadogCore/Sources/Core/DatadogCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,10 @@ extension DatadogContextProvider {
subscribe(\.isLowPowerModeEnabled, to: LowPowerModePublisher(notificationCenter: notificationCenter, processInfo: processInfo))
#endif

#if os(iOS)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there anything for tvOS on that front?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this should be available on tvOS as well!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey! Actually I checked on the documentation and it's not available for tvOS.

subscribe(\.brightnessLevel, to: BrightnessLevelPublisher(notificationCenter: notificationCenter))
#endif

#if os(iOS) || os(tvOS)
DispatchQueue.main.async {
// must be call on the main thread to read `UIApplication.State`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2019-Present Datadog, Inc.
*/

#if os(iOS)

import XCTest
@testable import TestUtilities
@testable import DatadogCore

final class BrightnessLevelPublisherTests: XCTestCase {
private let notificationCenter = MockNotificationCenter()

func testInitialValue() throws {
// Given
let publisher = BrightnessLevelPublisher(notificationCenter: notificationCenter)

// Then
XCTAssertNotNil(publisher.initialValue)
XCTAssertEqual(publisher.initialValue, Float(UIScreen.main.brightness))
}

func testMultipleBrightnessChanges() throws {
let expectation1 = self.expectation(description: "first brightness change")
let expectation2 = self.expectation(description: "second brightness change")

// Given
let mockScreen = UIScreenMock(brightness: 0.2)
let publisher = BrightnessLevelPublisher(notificationCenter: notificationCenter, screen: mockScreen)
var receivedValues: [Float] = []

publisher.publish { level in
if let level = level {
receivedValues.append(level)

switch receivedValues.count {
case 1:
expectation1.fulfill()
case 2:
expectation2.fulfill()
default:
break
}
}
}

// When
mockScreen.brightness = 0.5
notificationCenter.postFakeNotification(name: UIScreen.brightnessDidChangeNotification)
mockScreen.brightness = 0.8
notificationCenter.postFakeNotification(name: UIScreen.brightnessDidChangeNotification)

wait(for: [expectation1, expectation2], timeout: 0.1)

// Then
XCTAssertEqual(receivedValues.count, 3)
XCTAssertEqual(receivedValues[0], 0.2)
XCTAssertEqual(receivedValues[1], 0.5)
XCTAssertEqual(receivedValues[2], 0.8)
}
}

#endif
10 changes: 10 additions & 0 deletions DatadogInternal/Sources/Context/BrightnessLevel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2019-Present Datadog, Inc.
*/

import Foundation

/// Type alias for screen brightness level for mobile devices.
public typealias BrightnessLevel = Float
5 changes: 5 additions & 0 deletions DatadogInternal/Sources/Context/DatadogContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ public struct DatadogContext {
/// This value can be `nil` of the current device battery interface is not available.
public var batteryStatus: BatteryStatus?

/// The current brightness status.
public var brightnessLevel: BrightnessLevel?

/// `true` if the Low Power Mode is enabled.
public var isLowPowerModeEnabled = false

Expand Down Expand Up @@ -141,6 +144,7 @@ public struct DatadogContext {
networkConnectionInfo: NetworkConnectionInfo? = nil,
carrierInfo: CarrierInfo? = nil,
batteryStatus: BatteryStatus? = nil,
brightnessLevel: BrightnessLevel? = nil,
isLowPowerModeEnabled: Bool = false,
additionalContext: [String: AdditionalContext] = [:]
) {
Expand Down Expand Up @@ -170,6 +174,7 @@ public struct DatadogContext {
self.networkConnectionInfo = networkConnectionInfo
self.carrierInfo = carrierInfo
self.batteryStatus = batteryStatus
self.brightnessLevel = brightnessLevel
self.isLowPowerModeEnabled = isLowPowerModeEnabled
self.additionalContext = additionalContext
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,17 @@ public struct CrashContext: Codable, Equatable {
/// not support telephony services.
public let carrierInfo: CarrierInfo?

/// The current mobile device battery status.
///
/// This value can be `nil` of the current device battery interface is not available.
public var batteryStatus: BatteryStatus?

/// The current brightness status.
public var brightnessLevel: BrightnessLevel?

/// `true` if the Low Power Mode is enabled.
public var isLowPowerModeEnabled = false

/// The last _"Is app in foreground?"_ information from crashed app process.
public let lastIsAppInForeground: Bool

Expand Down Expand Up @@ -96,6 +107,9 @@ public struct CrashContext: Codable, Equatable {
accountInfo: AccountInfo?,
networkConnectionInfo: NetworkConnectionInfo?,
carrierInfo: CarrierInfo?,
batteryStatus: BatteryStatus?,
brightnessLevel: BrightnessLevel?,
isLowPowerModeEnabled: Bool,
lastIsAppInForeground: Bool,
appLaunchDate: Date?,
lastRUMViewEvent: RUMViewEvent?,
Expand All @@ -116,6 +130,9 @@ public struct CrashContext: Codable, Equatable {
self.accountInfo = accountInfo
self.networkConnectionInfo = networkConnectionInfo
self.carrierInfo = carrierInfo
self.batteryStatus = batteryStatus
self.brightnessLevel = brightnessLevel
self.isLowPowerModeEnabled = isLowPowerModeEnabled
self.lastIsAppInForeground = lastIsAppInForeground
self.appLaunchDate = appLaunchDate
self.lastRUMViewEvent = lastRUMViewEvent
Expand Down
Loading