// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import Foundation import IOKit.ps enum PowerState { case ac case battery case unknown } /// A convenience wrapper for an IOKit power source. final class PowerSource { let info = IOPSCopyPowerSourcesInfo().takeRetainedValue() let sources: Array init() { sources = IOPSCopyPowerSourcesList(info).takeRetainedValue() as Array } func hasBattery() -> Bool { return !sources.isEmpty } /// Returns the current power source capacity. Apple-defined power sources will return this value /// as a percentage. func getCurrentCapacity() -> Int? { if let source = sources.first { let description = IOPSGetPowerSourceDescription(info, source).takeUnretainedValue() as! [String: AnyObject] if let level = description[kIOPSCurrentCapacityKey] as? Int { return level } } return nil } /// Returns whether the device is drawing battery power or connected to an external power source. func getPowerState() -> PowerState { if let source = sources.first { let description = IOPSGetPowerSourceDescription(info, source).takeUnretainedValue() as! [String: AnyObject] if let state = description[kIOPSPowerSourceStateKey] as? String { switch state { case kIOPSACPowerValue: return .ac case kIOPSBatteryPowerValue: return .battery default: return .unknown } } } return .unknown } } protocol PowerSourceStateChangeDelegate: AnyObject { func didChangePowerSourceState() } /// A listener for system power source state change events. Notifies the delegate on each event. final class PowerSourceStateChangeHandler { private var runLoopSource: CFRunLoopSource? weak var delegate: PowerSourceStateChangeDelegate? init() { let context = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()) self.runLoopSource = IOPSNotificationCreateRunLoopSource( { (context: UnsafeMutableRawPointer?) in let unownedSelf = Unmanaged.fromOpaque( UnsafeRawPointer(context!) ).takeUnretainedValue() unownedSelf.delegate?.didChangePowerSourceState() }, context ).takeRetainedValue() CFRunLoopAddSource(CFRunLoopGetCurrent(), self.runLoopSource, .defaultMode) } deinit { CFRunLoopRemoveSource(CFRunLoopGetCurrent(), self.runLoopSource, .defaultMode) } }