| // 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<CFTypeRef> |
| |
| 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<PowerSourceStateChangeHandler>.fromOpaque( |
| UnsafeRawPointer(context!) |
| ).takeUnretainedValue() |
| unownedSelf.delegate?.didChangePowerSourceState() |
| }, context |
| ).takeRetainedValue() |
| CFRunLoopAddSource(CFRunLoopGetCurrent(), self.runLoopSource, .defaultMode) |
| } |
| |
| deinit { |
| CFRunLoopRemoveSource(CFRunLoopGetCurrent(), self.runLoopSource, .defaultMode) |
| } |
| } |