Add DeviceBatteryLevelManager
This commit is contained in:
parent
44e6771c8d
commit
25b4f617ca
@ -1190,6 +1190,8 @@
|
||||
66F6D6A52C7D0E0000EFAF75 /* ColorOrGradient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66F6D6A42C7D0E0000EFAF75 /* ColorOrGradient.swift */; };
|
||||
66F6D6A72C7D0FF300EFAF75 /* Wallpaper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66F6D6A62C7D0FF300EFAF75 /* Wallpaper.swift */; };
|
||||
66F6D6A92C7D106100EFAF75 /* Wallpaper+Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66F6D6A82C7D106100EFAF75 /* Wallpaper+Constants.swift */; };
|
||||
66F98DE02DB710F8009F1A86 /* DeviceBatteryLevelManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66F98DDF2DB710EA009F1A86 /* DeviceBatteryLevelManager.swift */; };
|
||||
66F98DE22DB71220009F1A86 /* DeviceBatteryLevelManagerImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66F98DE12DB71219009F1A86 /* DeviceBatteryLevelManagerImpl.swift */; };
|
||||
66FA2B1D28CB0DE1006845CD /* PaymentsBiometryLockPromptViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66FA2B1C28CB0DE1006845CD /* PaymentsBiometryLockPromptViewController.swift */; };
|
||||
66FBC4E128DA820900BD9E8B /* MyStorySettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66FBC4E028DA820900BD9E8B /* MyStorySettingsViewController.swift */; };
|
||||
66FBC4E328DA82AA00BD9E8B /* SelectMyStoryRecipientsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66FBC4E228DA82AA00BD9E8B /* SelectMyStoryRecipientsViewController.swift */; };
|
||||
@ -5097,6 +5099,8 @@
|
||||
66F6D6A42C7D0E0000EFAF75 /* ColorOrGradient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorOrGradient.swift; sourceTree = "<group>"; };
|
||||
66F6D6A62C7D0FF300EFAF75 /* Wallpaper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wallpaper.swift; sourceTree = "<group>"; };
|
||||
66F6D6A82C7D106100EFAF75 /* Wallpaper+Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Wallpaper+Constants.swift"; sourceTree = "<group>"; };
|
||||
66F98DDF2DB710EA009F1A86 /* DeviceBatteryLevelManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceBatteryLevelManager.swift; sourceTree = "<group>"; };
|
||||
66F98DE12DB71219009F1A86 /* DeviceBatteryLevelManagerImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceBatteryLevelManagerImpl.swift; sourceTree = "<group>"; };
|
||||
66FA2B1C28CB0DE1006845CD /* PaymentsBiometryLockPromptViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentsBiometryLockPromptViewController.swift; sourceTree = "<group>"; };
|
||||
66FA2B1E28CBA4A5006845CD /* DeviceOwnerAuthenticationType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceOwnerAuthenticationType.swift; sourceTree = "<group>"; };
|
||||
66FBC4E028DA820900BD9E8B /* MyStorySettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyStorySettingsViewController.swift; sourceTree = "<group>"; };
|
||||
@ -10420,6 +10424,7 @@
|
||||
4C751BE423FA0284002A8AF1 /* ContactSupportActionSheet.swift */,
|
||||
50A1CE392A00931900730C40 /* DebugLogger+MainApp.swift */,
|
||||
34067EAA2710D61A000407C3 /* DebugLogs.swift */,
|
||||
66F98DE12DB71219009F1A86 /* DeviceBatteryLevelManagerImpl.swift */,
|
||||
505347F82DA08548004AF0B5 /* DeviceSleepManagerImpl.swift */,
|
||||
34A95500271B503E00B05242 /* DisplayableText.swift */,
|
||||
F9D289B5291EDC8D00187394 /* DonationJobError.swift */,
|
||||
@ -14271,6 +14276,7 @@
|
||||
F94C912128FDEAF50065DF75 /* Decimal+IsInteger.swift */,
|
||||
F94C911F28FDEA2E0065DF75 /* Decimal+Rounded.swift */,
|
||||
F9C5CB79289453B200548EEE /* DecodableDefaults.swift */,
|
||||
66F98DDF2DB710EA009F1A86 /* DeviceBatteryLevelManager.swift */,
|
||||
F9C5CB3A289453B200548EEE /* DeviceNames.swift */,
|
||||
66FA2B1E28CBA4A5006845CD /* DeviceOwnerAuthenticationType.swift */,
|
||||
348F2EAD1F0D21BC00D4ECE0 /* DeviceSleepManager.swift */,
|
||||
@ -16868,6 +16874,7 @@
|
||||
887B6DC925F6C3E900E677D4 /* DeleteAccountConfirmationViewController.swift in Sources */,
|
||||
D9E8EDF32C0FD8C800923E3C /* DeleteForMeInfoSheetCoordinator.swift in Sources */,
|
||||
D9E8EDF12C0FCB3000923E3C /* DeleteForMeSyncMessageInfoSheet.swift in Sources */,
|
||||
66F98DE22DB71220009F1A86 /* DeviceBatteryLevelManagerImpl.swift in Sources */,
|
||||
C17A54982D7B3DCD00E1D267 /* DeviceProvisioningURL.swift in Sources */,
|
||||
505347F92DA08548004AF0B5 /* DeviceSleepManagerImpl.swift in Sources */,
|
||||
887CD4772472FEA500FDD265 /* DeviceTransferOperation.swift in Sources */,
|
||||
@ -17611,6 +17618,7 @@
|
||||
D9247EA82BFD28E800DFEF6F /* DeleteForMeSyncMessageReceiver.swift in Sources */,
|
||||
F9C5CC34289453B300548EEE /* DeliveryReceiptContext.swift in Sources */,
|
||||
6698FC1A2980AB45004EFC30 /* DependenciesBridge.swift in Sources */,
|
||||
66F98DE02DB710F8009F1A86 /* DeviceBatteryLevelManager.swift in Sources */,
|
||||
50F401CC2D483BF40094CA56 /* DeviceId.swift in Sources */,
|
||||
505C2ED629971D4E00C23FB2 /* DeviceLimitExceededError.swift in Sources */,
|
||||
50E5E4B129932D9B00E15A1C /* DeviceMessage.swift in Sources */,
|
||||
|
||||
@ -183,6 +183,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
MessageFetchBGRefreshTask.register(appReadiness: appReadiness)
|
||||
|
||||
let deviceBatteryLevelManager = DeviceBatteryLevelManagerImpl()
|
||||
let deviceSleepManager = DeviceSleepManagerImpl()
|
||||
let keychainStorage = KeychainStorageImpl(isUsingProductionService: TSConstants.isUsingProductionService)
|
||||
let deviceTransferService = DeviceTransferService(
|
||||
@ -255,6 +256,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
let launchContext = LaunchContext(
|
||||
appContext: mainAppContext,
|
||||
databaseStorage: databaseStorage,
|
||||
deviceBatteryLevelManager: deviceBatteryLevelManager,
|
||||
deviceSleepManager: deviceSleepManager,
|
||||
keychainStorage: keychainStorage,
|
||||
launchStartedAt: launchStartedAt,
|
||||
@ -368,6 +370,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
private struct LaunchContext {
|
||||
var appContext: MainAppContext
|
||||
var databaseStorage: SDSDatabaseStorage
|
||||
var deviceBatteryLevelManager: DeviceBatteryLevelManagerImpl
|
||||
var deviceSleepManager: DeviceSleepManagerImpl
|
||||
var keychainStorage: any KeychainStorage
|
||||
var launchStartedAt: CFTimeInterval
|
||||
@ -412,6 +415,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
appContext: launchContext.appContext,
|
||||
appReadiness: appReadiness,
|
||||
databaseStorage: launchContext.databaseStorage,
|
||||
deviceBatteryLevelManager: launchContext.deviceBatteryLevelManager,
|
||||
deviceSleepManager: launchContext.deviceSleepManager,
|
||||
paymentsEvents: PaymentsEventsMainApp(),
|
||||
mobileCoinHelper: MobileCoinHelperSDK(),
|
||||
|
||||
72
Signal/util/DeviceBatteryLevelManagerImpl.swift
Normal file
72
Signal/util/DeviceBatteryLevelManagerImpl.swift
Normal file
@ -0,0 +1,72 @@
|
||||
//
|
||||
// Copyright 2025 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
public import SignalServiceKit
|
||||
|
||||
public class DeviceBatteryLevelMonitorImpl: DeviceBatteryLevelMonitor {
|
||||
|
||||
fileprivate let reason: String
|
||||
fileprivate var wasReleased: Bool = false
|
||||
|
||||
fileprivate init(reason: String) {
|
||||
self.reason = reason
|
||||
}
|
||||
|
||||
deinit {
|
||||
if !wasReleased {
|
||||
owsFailDebug("End battery monitoring before releasing ref!")
|
||||
}
|
||||
}
|
||||
|
||||
public var batteryLevel: Float {
|
||||
// On simulators, the battery level always reports -1.0 (invalid).
|
||||
if Platform.isSimulator {
|
||||
return 1
|
||||
} else {
|
||||
return UIDevice.current.batteryLevel
|
||||
}
|
||||
}
|
||||
|
||||
public var notification: Notification.Name { UIDevice.batteryLevelDidChangeNotification }
|
||||
}
|
||||
|
||||
public class DeviceBatteryLevelManagerImpl: DeviceBatteryLevelManager {
|
||||
|
||||
private var reasons = Set<String>()
|
||||
|
||||
public init() {}
|
||||
|
||||
public func beginMonitoring(reason: String) -> DeviceBatteryLevelMonitor {
|
||||
if reasons.isEmpty {
|
||||
UIDevice.current.isBatteryMonitoringEnabled = true
|
||||
}
|
||||
let (duplicate, _) = reasons.insert(reason)
|
||||
if !duplicate {
|
||||
owsFailDebug("Duplicate monitoring reason!")
|
||||
}
|
||||
return DeviceBatteryLevelMonitorImpl(
|
||||
reason: reason
|
||||
)
|
||||
}
|
||||
|
||||
public func endMonitoring(_ monitor: DeviceBatteryLevelMonitor) {
|
||||
guard let monitor = monitor as? DeviceBatteryLevelMonitorImpl else {
|
||||
owsFailDebug("Invalid type combination")
|
||||
return
|
||||
}
|
||||
if monitor.wasReleased {
|
||||
owsFailDebug("Ending monitoring twice!")
|
||||
}
|
||||
reasons.remove(monitor.reason)
|
||||
monitor.wasReleased = true
|
||||
if reasons.isEmpty {
|
||||
UIDevice.current.isBatteryMonitoringEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
public var isLowPowerModeEnabled: Bool { ProcessInfo.processInfo.isLowPowerModeEnabled }
|
||||
|
||||
public var isLowPowerModeChangedNotification: Notification.Name { .NSProcessInfoPowerStateDidChange }
|
||||
}
|
||||
@ -144,6 +144,7 @@ class NSEEnvironment {
|
||||
appContext: CurrentAppContext(),
|
||||
appReadiness: appReadiness,
|
||||
databaseStorage: databaseStorage,
|
||||
deviceBatteryLevelManager: nil,
|
||||
deviceSleepManager: nil,
|
||||
paymentsEvents: PaymentsEventsAppExtension(),
|
||||
mobileCoinHelper: MobileCoinHelperMinimal(),
|
||||
|
||||
@ -92,6 +92,7 @@ public class AppSetup {
|
||||
appContext: AppContext,
|
||||
appReadiness: AppReadiness,
|
||||
databaseStorage: SDSDatabaseStorage,
|
||||
deviceBatteryLevelManager: (any DeviceBatteryLevelManager)?,
|
||||
deviceSleepManager: (any DeviceSleepManager)?,
|
||||
paymentsEvents: PaymentsEvents,
|
||||
mobileCoinHelper: MobileCoinHelper,
|
||||
@ -948,6 +949,7 @@ public class AppSetup {
|
||||
backupAttachmentDownloadStore: backupAttachmentDownloadStore,
|
||||
dateProvider: dateProvider,
|
||||
db: db,
|
||||
deviceBatteryLevelManager: deviceBatteryLevelManager,
|
||||
mediaBandwidthPreferenceStore: mediaBandwidthPreferenceStore,
|
||||
messageBackupKeyMaterial: messageBackupKeyMaterial,
|
||||
messageBackupRequestManager: messageBackupRequestManager,
|
||||
|
||||
@ -46,6 +46,7 @@ public class BackupAttachmentDownloadManagerImpl: BackupAttachmentDownloadManage
|
||||
private let backupAttachmentDownloadStore: BackupAttachmentDownloadStore
|
||||
private let dateProvider: DateProvider
|
||||
private let db: any DB
|
||||
private let deviceBatteryLevelManager: (any DeviceBatteryLevelManager)?
|
||||
private let listMediaManager: ListMediaManager
|
||||
private let mediaBandwidthPreferenceStore: MediaBandwidthPreferenceStore
|
||||
private let reachabilityManager: SSKReachabilityManager
|
||||
@ -63,6 +64,7 @@ public class BackupAttachmentDownloadManagerImpl: BackupAttachmentDownloadManage
|
||||
backupAttachmentDownloadStore: BackupAttachmentDownloadStore,
|
||||
dateProvider: @escaping DateProvider,
|
||||
db: any DB,
|
||||
deviceBatteryLevelManager: (any DeviceBatteryLevelManager)?,
|
||||
mediaBandwidthPreferenceStore: MediaBandwidthPreferenceStore,
|
||||
messageBackupKeyMaterial: MessageBackupKeyMaterial,
|
||||
messageBackupRequestManager: MessageBackupRequestManager,
|
||||
@ -76,6 +78,7 @@ public class BackupAttachmentDownloadManagerImpl: BackupAttachmentDownloadManage
|
||||
self.backupAttachmentDownloadStore = backupAttachmentDownloadStore
|
||||
self.dateProvider = dateProvider
|
||||
self.db = db
|
||||
self.deviceBatteryLevelManager = deviceBatteryLevelManager
|
||||
self.mediaBandwidthPreferenceStore = mediaBandwidthPreferenceStore
|
||||
self.reachabilityManager = reachabilityManager
|
||||
self.remoteConfigProvider = remoteConfigProvider
|
||||
|
||||
@ -42,6 +42,7 @@ public class MockSSKEnvironment {
|
||||
databaseFileUrl: SDSDatabaseStorage.grdbDatabaseFileUrl,
|
||||
keychainStorage: MockKeychainStorage()
|
||||
),
|
||||
deviceBatteryLevelManager: nil,
|
||||
deviceSleepManager: nil,
|
||||
paymentsEvents: PaymentsEventsNoop(),
|
||||
mobileCoinHelper: MobileCoinHelperMock(),
|
||||
|
||||
31
SignalServiceKit/Util/DeviceBatteryLevelManager.swift
Normal file
31
SignalServiceKit/Util/DeviceBatteryLevelManager.swift
Normal file
@ -0,0 +1,31 @@
|
||||
//
|
||||
// Copyright 2025 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@MainActor
|
||||
public protocol DeviceBatteryLevelMonitor {
|
||||
/// A value from 0 to 1
|
||||
var batteryLevel: Float { get }
|
||||
|
||||
/// Notification fired on NotificationCenter.default when the battery level changes.
|
||||
var notification: Notification.Name { get }
|
||||
}
|
||||
|
||||
@MainActor
|
||||
public protocol DeviceBatteryLevelManager {
|
||||
|
||||
/// Setting `UIDevice.isBatteryMonitoringEnabled` incurs a cost and Apple would like we
|
||||
/// only do it as strictly needed. To manage this app wide, use a unique reason string. As long
|
||||
/// as some monitor is active, battery monitoring will be enabled (thus allowing checking the
|
||||
/// current battery level and getting battery level change notifications).
|
||||
func beginMonitoring(reason: String) -> DeviceBatteryLevelMonitor
|
||||
|
||||
/// MUST call this before releasing the reference to the DeviceBatteryLevelMonitor from `beginMonitoring`.
|
||||
func endMonitoring(_ monitor: DeviceBatteryLevelMonitor)
|
||||
|
||||
var isLowPowerModeEnabled: Bool { get }
|
||||
var isLowPowerModeChangedNotification: Notification.Name { get }
|
||||
}
|
||||
@ -59,6 +59,7 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
|
||||
appContext: appContext,
|
||||
appReadiness: appReadiness,
|
||||
databaseStorage: databaseStorage,
|
||||
deviceBatteryLevelManager: nil,
|
||||
deviceSleepManager: nil,
|
||||
paymentsEvents: PaymentsEventsAppExtension(),
|
||||
mobileCoinHelper: MobileCoinHelperMinimal(),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user