TM-SGNL-iOS/SignalServiceKit/Util/ProximityMonitoringManager.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07:00

93 lines
3 KiB
Swift

//
// Copyright 2018 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
public protocol OWSProximityMonitoringManager: AnyObject {
func add(lifetime: AnyObject)
func remove(lifetime: AnyObject)
}
public class OWSProximityMonitoringManagerImpl: OWSProximityMonitoringManager {
public init() {}
private struct State {
var didAddObserver = false
var lifetimes = [Weak<AnyObject>]()
}
private var state = AtomicValue(State(), lock: .init())
public func add(lifetime: AnyObject) {
guard !CurrentAppContext().isNSE else {
return
}
updateState { state in
if state.lifetimes.contains(where: { $0.value === lifetime }) {
return
}
state.lifetimes.append(Weak(value: lifetime))
}
}
public func remove(lifetime: AnyObject) {
guard !CurrentAppContext().isNSE else {
return
}
updateState { state in
state.lifetimes = state.lifetimes.filter { $0.value !== lifetime }
}
}
private func updateState(block: (inout State) -> Void) {
state.update { mutableState in
let oldEnabled = !mutableState.lifetimes.isEmpty
block(&mutableState)
mutableState.lifetimes = mutableState.lifetimes.filter { $0.value !== nil }
let newEnabled = !mutableState.lifetimes.isEmpty
if oldEnabled == newEnabled {
return
}
didChangeEnabled(newValue: newEnabled, state: &mutableState)
}
}
@objc
private func proximitySensorStateDidChange(notification: Notification) {
Logger.debug("")
// This is crazy, but if we disable `device.isProximityMonitoringEnabled`
// while `device.proximityState` is true (while the device is held to the
// ear) then `device.proximityState` remains true, even after we bring the
// phone away from the ear and re-enable monitoring.
//
// To resolve this, we wait to disable proximity monitoring until
// `proximityState` is false.
if UIDevice.current.proximityState {
self.add(lifetime: self)
} else {
self.remove(lifetime: self)
}
}
private func didChangeEnabled(newValue: Bool, state: inout State) {
Logger.debug("Proximity monitoring changed to \(newValue)")
if newValue, !state.didAddObserver {
state.didAddObserver = true
DispatchQueue.main.async {
NotificationCenter.default.addObserver(
self,
selector: #selector(self.proximitySensorStateDidChange(notification:)),
name: UIDevice.proximityStateDidChangeNotification,
object: nil
)
}
}
DispatchQueue.main.async {
UIDevice.current.isProximityMonitoringEnabled = newValue
}
}
}