Skip to content

Commit da7046c

Browse files
RUM-10378 Collect battery attributes
1 parent d4ca258 commit da7046c

File tree

14 files changed

+930
-60
lines changed

14 files changed

+930
-60
lines changed

Datadog/Datadog.xcodeproj/project.pbxproj

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,12 +849,18 @@
849849
86092FDE2DEDC6830075D63B /* AccessibilityValuesMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86092FDC2DEDC6830075D63B /* AccessibilityValuesMock.swift */; };
850850
862B0B272DEF2D8000F61E73 /* MockNotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 862B0B262DEF2D8000F61E73 /* MockNotificationCenter.swift */; };
851851
862B0B282DEF2D8000F61E73 /* MockNotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 862B0B262DEF2D8000F61E73 /* MockNotificationCenter.swift */; };
852+
8648D0782E01A389002F226B /* BrightnessStatusPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8648D0772E01A389002F226B /* BrightnessStatusPublisher.swift */; };
853+
8648D0792E01A389002F226B /* BrightnessStatusPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8648D0772E01A389002F226B /* BrightnessStatusPublisher.swift */; };
854+
8648D07B2E01ABB0002F226B /* BrightnessStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8648D07A2E01ABB0002F226B /* BrightnessStatus.swift */; };
855+
8648D07C2E01ABB0002F226B /* BrightnessStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8648D07A2E01ABB0002F226B /* BrightnessStatus.swift */; };
852856
864A70792DDF742A00AC0619 /* Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864A70782DDF742A00AC0619 /* Accessibility.swift */; };
853857
864A707A2DDF742A00AC0619 /* Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864A70782DDF742A00AC0619 /* Accessibility.swift */; };
854858
864A707C2DDF743900AC0619 /* AccessibilityReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864A707B2DDF743900AC0619 /* AccessibilityReader.swift */; };
855859
864A707D2DDF743900AC0619 /* AccessibilityReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864A707B2DDF743900AC0619 /* AccessibilityReader.swift */; };
856860
864A70802DE092AD00AC0619 /* AccessibilityReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864A707E2DE092AD00AC0619 /* AccessibilityReaderTests.swift */; };
857861
864A70812DE092AD00AC0619 /* AccessibilityReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864A707E2DE092AD00AC0619 /* AccessibilityReaderTests.swift */; };
862+
866CA4A82E02EE0100E0CD03 /* BrightnessStatusPublisherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 866CA4A72E02EE0100E0CD03 /* BrightnessStatusPublisherTests.swift */; };
863+
866CA4A92E02EE0100E0CD03 /* BrightnessStatusPublisherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 866CA4A72E02EE0100E0CD03 /* BrightnessStatusPublisherTests.swift */; };
858864
960A0D3B2D6E2490004BB999 /* Reflector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 960A0D3A2D6E2490004BB999 /* Reflector.swift */; };
859865
960A0D3C2D6E2490004BB999 /* CustomDump.swift in Sources */ = {isa = PBXBuildFile; fileRef = 960A0D382D6E2490004BB999 /* CustomDump.swift */; };
860866
960A0D3D2D6E2490004BB999 /* ReflectionMirror.swift in Sources */ = {isa = PBXBuildFile; fileRef = 960A0D392D6E2490004BB999 /* ReflectionMirror.swift */; };
@@ -2952,9 +2958,12 @@
29522958
61FF9A4425AC5DEA001058CC /* ViewIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewIdentifier.swift; sourceTree = "<group>"; };
29532959
86092FDC2DEDC6830075D63B /* AccessibilityValuesMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityValuesMock.swift; sourceTree = "<group>"; };
29542960
862B0B262DEF2D8000F61E73 /* MockNotificationCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockNotificationCenter.swift; sourceTree = "<group>"; };
2961+
8648D0772E01A389002F226B /* BrightnessStatusPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrightnessStatusPublisher.swift; sourceTree = "<group>"; };
2962+
8648D07A2E01ABB0002F226B /* BrightnessStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrightnessStatus.swift; sourceTree = "<group>"; };
29552963
864A70782DDF742A00AC0619 /* Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Accessibility.swift; sourceTree = "<group>"; };
29562964
864A707B2DDF743900AC0619 /* AccessibilityReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityReader.swift; sourceTree = "<group>"; };
29572965
864A707E2DE092AD00AC0619 /* AccessibilityReaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityReaderTests.swift; sourceTree = "<group>"; };
2966+
866CA4A72E02EE0100E0CD03 /* BrightnessStatusPublisherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrightnessStatusPublisherTests.swift; sourceTree = "<group>"; };
29582967
960A0D382D6E2490004BB999 /* CustomDump.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDump.swift; sourceTree = "<group>"; };
29592968
960A0D392D6E2490004BB999 /* ReflectionMirror.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReflectionMirror.swift; sourceTree = "<group>"; };
29602969
960A0D3A2D6E2490004BB999 /* Reflector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reflector.swift; sourceTree = "<group>"; };
@@ -5435,6 +5444,7 @@
54355444
D26C49AE2886DC7B00802B2D /* ApplicationStatePublisherTests.swift */,
54365445
D2C7E3AA28F97DCF0023B2CC /* BatteryStatusPublisherTests.swift */,
54375446
D234613028B7712F00055D4C /* FeatureContextTests.swift */,
5447+
866CA4A72E02EE0100E0CD03 /* BrightnessStatusPublisherTests.swift */,
54385448
);
54395449
path = Context;
54405450
sourceTree = "<group>";
@@ -6229,6 +6239,7 @@
62296239
D23039BE298D5235001A1FA3 /* LaunchTime.swift */,
62306240
D2F8235229915E12003C7E99 /* DatadogSite.swift */,
62316241
6174D6122BFDF16C00EC7469 /* BundleType.swift */,
6242+
8648D07A2E01ABB0002F226B /* BrightnessStatus.swift */,
62326243
);
62336244
path = Context;
62346245
sourceTree = "<group>";
@@ -6790,6 +6801,7 @@
67906801
D2EFA867286DA85700F1FAA6 /* DatadogContextProvider.swift */,
67916802
D20605A2287464F40047275C /* ContextValuePublisher.swift */,
67926803
D20605A5287476230047275C /* ServerOffsetPublisher.swift */,
6804+
8648D0772E01A389002F226B /* BrightnessStatusPublisher.swift */,
67936805
D20605A82874C1CD0047275C /* NetworkConnectionInfoPublisher.swift */,
67946806
D20605B12874E1660047275C /* CarrierInfoPublisher.swift */,
67956807
D2A1EE31287DA51900D28DFB /* UserInfoPublisher.swift */,
@@ -8373,6 +8385,7 @@
83738385
D26C49BF288982DA00802B2D /* FeatureUpload.swift in Sources */,
83748386
A70A82652A935F210072F5DC /* BackgroundTaskCoordinator.swift in Sources */,
83758387
61D3E0D2277B23F1008BE766 /* KronosInternetAddress.swift in Sources */,
8388+
8648D0782E01A389002F226B /* BrightnessStatusPublisher.swift in Sources */,
83768389
D2553826288F0B1A00727FAD /* BatteryStatusPublisher.swift in Sources */,
83778390
61D3E0D5277B23F1008BE766 /* KronosNTPPacket.swift in Sources */,
83788391
6128F5712BA223D100D35B08 /* DataStore+TLV.swift in Sources */,
@@ -8463,6 +8476,7 @@
84638476
61133C582423990D00786299 /* FileWriterTests.swift in Sources */,
84648477
D22743DC29DEB8B4001A7EF9 /* VitalRefreshRateReaderTests.swift in Sources */,
84658478
617B954224BF4E7600E6F443 /* RUMMonitorConfigurationTests.swift in Sources */,
8479+
866CA4A92E02EE0100E0CD03 /* BrightnessStatusPublisherTests.swift in Sources */,
84668480
3C0D5DE22A543DC400446CF9 /* EventGeneratorTests.swift in Sources */,
84678481
6136CB4A2A69C29C00AC265D /* FilesOrchestrator+MetricsTests.swift in Sources */,
84688482
266BFA5E2D6F4E31003041A5 /* AccountInfoPublisherTests.swift in Sources */,
@@ -8974,6 +8988,7 @@
89748988
D2303A01298D5236001A1FA3 /* DateFormatting.swift in Sources */,
89758989
D23039F1298D5236001A1FA3 /* AnyDecodable.swift in Sources */,
89768990
6167E6E22B81207200C3CA2D /* DDCrashReport.swift in Sources */,
8991+
8648D07B2E01ABB0002F226B /* BrightnessStatus.swift in Sources */,
89778992
D2160CC529C0DED100FAA9A5 /* URLSessionTaskInterception.swift in Sources */,
89788993
6167E6FD2B81EC0400C3CA2D /* BacktraceReporter.swift in Sources */,
89798994
D23039DD298D5235001A1FA3 /* DD.swift in Sources */,
@@ -9747,6 +9762,7 @@
97479762
D2612F48290197C700509B7D /* LaunchTimePublisher.swift in Sources */,
97489763
A70A82662A935F210072F5DC /* BackgroundTaskCoordinator.swift in Sources */,
97499764
D2A1EE24287740B500D28DFB /* ApplicationStatePublisher.swift in Sources */,
9765+
8648D0792E01A389002F226B /* BrightnessStatusPublisher.swift in Sources */,
97509766
D2CB6E2927C50EAE00A62B57 /* KronosInternetAddress.swift in Sources */,
97519767
6128F5722BA223D100D35B08 /* DataStore+TLV.swift in Sources */,
97529768
D2CB6E2C27C50EAE00A62B57 /* KronosNTPPacket.swift in Sources */,
@@ -9857,6 +9873,7 @@
98579873
D2CB6F1A27C520D400A62B57 /* FileReaderTests.swift in Sources */,
98589874
266BFA5F2D6F4E31003041A5 /* AccountInfoPublisherTests.swift in Sources */,
98599875
D2777D9E29F6A75800FFBB40 /* TelemetryReceiverTests.swift in Sources */,
9876+
866CA4A82E02EE0100E0CD03 /* BrightnessStatusPublisherTests.swift in Sources */,
98609877
D2A1EE39287EEB7600D28DFB /* NetworkConnectionInfoPublisherTests.swift in Sources */,
98619878
D2CB6F1D27C520D400A62B57 /* DataUploaderTests.swift in Sources */,
98629879
D2A1EE35287EB8DB00D28DFB /* ServerOffsetPublisherTests.swift in Sources */,
@@ -10079,6 +10096,7 @@
1007910096
6167E6E32B81207200C3CA2D /* DDCrashReport.swift in Sources */,
1008010097
D2160CC629C0DED100FAA9A5 /* URLSessionTaskInterception.swift in Sources */,
1008110098
6167E6FE2B81EC0400C3CA2D /* BacktraceReporter.swift in Sources */,
10099+
8648D07C2E01ABB0002F226B /* BrightnessStatus.swift in Sources */,
1008210100
D2DA2372298D57AA00C6C7E6 /* DD.swift in Sources */,
1008310101
D2160C9B29C0DE5700FAA9A5 /* FirstPartyHosts.swift in Sources */,
1008410102
D2EBEE3029BA161100B15732 /* TracePropagationHeadersReader.swift in Sources */,
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
* Copyright 2019-Present Datadog, Inc.
5+
*/
6+
7+
import Foundation
8+
import DatadogInternal
9+
10+
#if os(iOS)
11+
import UIKit
12+
13+
/// A publisher that publishes the screen brightness level from UIScreen.
14+
internal final class BrightnessStatusPublisher: ContextValuePublisher {
15+
/// The initial brightness level.
16+
let initialValue: BrightnessStatus?
17+
18+
/// The notification center to observe brightness changes.
19+
private let notificationCenter: NotificationCenter
20+
private let screen: UIScreen
21+
private var observers: [Any]? = nil
22+
23+
init(notificationCenter: NotificationCenter = .default, screen: UIScreen = .main) {
24+
self.notificationCenter = notificationCenter
25+
self.screen = screen
26+
self.initialValue = BrightnessStatus(level: Float(screen.brightness))
27+
}
28+
29+
/// Publishes the brightness level to the given receiver.
30+
///
31+
/// - Parameter receiver: The receiver to publish the brightness level to.
32+
func publish(to receiver: @escaping ContextValueReceiver<BrightnessStatus?>) {
33+
let block = { (notification: Notification) in
34+
receiver(BrightnessStatus(level: Float(self.screen.brightness)))
35+
}
36+
37+
observers = [
38+
notificationCenter.addObserver(
39+
forName: UIScreen.brightnessDidChangeNotification,
40+
object: nil,
41+
queue: .main,
42+
using: block
43+
)
44+
]
45+
46+
receiver(initialValue)
47+
}
48+
49+
func cancel() {
50+
observers?.forEach(notificationCenter.removeObserver)
51+
observers = nil
52+
}
53+
}
54+
55+
#endif

DatadogCore/Sources/Core/DatadogCore.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,8 @@ extension DatadogContextProvider {
525525
subscribe(\.isLowPowerModeEnabled, to: LowPowerModePublisher(notificationCenter: notificationCenter, processInfo: processInfo))
526526
#endif
527527

528+
subscribe(\.brightnessStatus, to: BrightnessStatusPublisher(notificationCenter: notificationCenter))
529+
528530
#if os(iOS) || os(tvOS)
529531
DispatchQueue.main.async {
530532
// must be call on the main thread to read `UIApplication.State`
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
* Copyright 2019-Present Datadog, Inc.
5+
*/
6+
7+
#if os(iOS)
8+
9+
import XCTest
10+
@testable import TestUtilities
11+
@testable import DatadogCore
12+
13+
final class BrightnessStatusPublisherTests: XCTestCase {
14+
private let notificationCenter = MockNotificationCenter()
15+
16+
func testInitialValue() throws {
17+
// Given
18+
let publisher = BrightnessStatusPublisher(notificationCenter: notificationCenter)
19+
20+
// Then
21+
XCTAssertNotNil(publisher.initialValue)
22+
XCTAssertEqual(publisher.initialValue?.level, Float(UIScreen.main.brightness))
23+
}
24+
25+
func testMultipleBrightnessChanges() throws {
26+
let expectation1 = self.expectation(description: "first brightness change")
27+
let expectation2 = self.expectation(description: "second brightness change")
28+
29+
// Given
30+
let mockScreen = UIScreenMock(brightness: 0.2)
31+
let publisher = BrightnessStatusPublisher(notificationCenter: notificationCenter, screen: mockScreen)
32+
var receivedValues: [Float] = []
33+
34+
publisher.publish { status in
35+
if let level = status?.level {
36+
receivedValues.append(level)
37+
38+
switch receivedValues.count {
39+
case 1:
40+
expectation1.fulfill()
41+
case 2:
42+
expectation2.fulfill()
43+
default:
44+
break
45+
}
46+
}
47+
}
48+
49+
// When
50+
mockScreen.brightness = 0.5
51+
notificationCenter.postFakeNotification(name: UIScreen.brightnessDidChangeNotification)
52+
mockScreen.brightness = 0.8
53+
notificationCenter.postFakeNotification(name: UIScreen.brightnessDidChangeNotification)
54+
55+
wait(for: [expectation1, expectation2], timeout: 0.1)
56+
57+
// Then
58+
XCTAssertEqual(receivedValues.count, 3)
59+
XCTAssertEqual(receivedValues[0], 0.2)
60+
XCTAssertEqual(receivedValues[1], 0.5)
61+
XCTAssertEqual(receivedValues[2], 0.8)
62+
}
63+
}
64+
65+
#endif
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
* Copyright 2019-Present Datadog, Inc.
5+
*/
6+
7+
import Foundation
8+
9+
/// Describe the battery state for mobile devices.
10+
public struct BrightnessStatus: Codable, Equatable {
11+
/// The brightness level
12+
public let level: Float
13+
14+
public init(level: Float) {
15+
self.level = level
16+
}
17+
}

DatadogInternal/Sources/Context/DatadogContext.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ public struct DatadogContext {
107107
/// This value can be `nil` of the current device battery interface is not available.
108108
public var batteryStatus: BatteryStatus?
109109

110+
/// The current brightness status.
111+
public var brightnessStatus: BrightnessStatus?
112+
110113
/// `true` if the Low Power Mode is enabled.
111114
public var isLowPowerModeEnabled = false
112115

@@ -141,6 +144,7 @@ public struct DatadogContext {
141144
networkConnectionInfo: NetworkConnectionInfo? = nil,
142145
carrierInfo: CarrierInfo? = nil,
143146
batteryStatus: BatteryStatus? = nil,
147+
brightnessStatus: BrightnessStatus? = nil,
144148
isLowPowerModeEnabled: Bool = false,
145149
additionalContext: [String: AdditionalContext] = [:]
146150
) {
@@ -170,6 +174,7 @@ public struct DatadogContext {
170174
self.networkConnectionInfo = networkConnectionInfo
171175
self.carrierInfo = carrierInfo
172176
self.batteryStatus = batteryStatus
177+
self.brightnessStatus = brightnessStatus
173178
self.isLowPowerModeEnabled = isLowPowerModeEnabled
174179
self.additionalContext = additionalContext
175180
}

DatadogInternal/Sources/Models/CrashReporting/CrashContext.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,17 @@ public struct CrashContext: Codable, Equatable {
6565
/// not support telephony services.
6666
public let carrierInfo: CarrierInfo?
6767

68+
/// The current mobile device battery status.
69+
///
70+
/// This value can be `nil` of the current device battery interface is not available.
71+
public var batteryStatus: BatteryStatus?
72+
73+
/// The current brightness status.
74+
public var brightnessStatus: BrightnessStatus?
75+
76+
/// `true` if the Low Power Mode is enabled.
77+
public var isLowPowerModeEnabled = false
78+
6879
/// The last _"Is app in foreground?"_ information from crashed app process.
6980
public let lastIsAppInForeground: Bool
7081

@@ -96,6 +107,9 @@ public struct CrashContext: Codable, Equatable {
96107
accountInfo: AccountInfo?,
97108
networkConnectionInfo: NetworkConnectionInfo?,
98109
carrierInfo: CarrierInfo?,
110+
batteryStatus: BatteryStatus?,
111+
brightnessStatus: BrightnessStatus?,
112+
isLowPowerModeEnabled: Bool,
99113
lastIsAppInForeground: Bool,
100114
appLaunchDate: Date?,
101115
lastRUMViewEvent: RUMViewEvent?,
@@ -116,6 +130,9 @@ public struct CrashContext: Codable, Equatable {
116130
self.accountInfo = accountInfo
117131
self.networkConnectionInfo = networkConnectionInfo
118132
self.carrierInfo = carrierInfo
133+
self.batteryStatus = batteryStatus
134+
self.brightnessStatus = brightnessStatus
135+
self.isLowPowerModeEnabled = isLowPowerModeEnabled
119136
self.lastIsAppInForeground = lastIsAppInForeground
120137
self.appLaunchDate = appLaunchDate
121138
self.lastRUMViewEvent = lastRUMViewEvent

0 commit comments

Comments
 (0)