PowerSource.swift 2.54 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// 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.
15
final class PowerSource {
16
  let info = IOPSCopyPowerSourcesInfo().takeRetainedValue()
17 18 19 20 21
  let sources: Array<CFTypeRef>

  init() {
    sources = IOPSCopyPowerSourcesList(info).takeRetainedValue() as Array
  }
22

23 24 25 26
  func hasBattery() -> Bool {
    return !sources.isEmpty
  }

27 28
  /// Returns the current power source capacity. Apple-defined power sources will return this value
  /// as a percentage.
29
  func getCurrentCapacity() -> Int? {
30 31 32 33 34 35 36
    if let source = sources.first {
      let description =
        IOPSGetPowerSourceDescription(info, source).takeUnretainedValue() as! [String: AnyObject]
      if let level = description[kIOPSCurrentCapacityKey] as? Int {
        return level
      }
    }
37
    return nil
38 39 40 41
  }

  /// Returns whether the device is drawing battery power or connected to an external power source.
  func getPowerState() -> PowerState {
42
    if let source = sources.first {
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
      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 {
61
  func didChangePowerSourceState()
62 63 64
}

/// A listener for system power source state change events. Notifies the delegate on each event.
65
final class PowerSourceStateChangeHandler {
66 67 68 69 70 71 72
  private var runLoopSource: CFRunLoopSource?
  weak var delegate: PowerSourceStateChangeDelegate?

  init() {
    let context = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
    self.runLoopSource = IOPSNotificationCreateRunLoopSource(
      { (context: UnsafeMutableRawPointer?) in
73
        let unownedSelf = Unmanaged<PowerSourceStateChangeHandler>.fromOpaque(
74 75
          UnsafeRawPointer(context!)
        ).takeUnretainedValue()
76
        unownedSelf.delegate?.didChangePowerSourceState()
77 78 79 80 81 82 83 84 85
      }, context
    ).takeRetainedValue()
    CFRunLoopAddSource(CFRunLoopGetCurrent(), self.runLoopSource, .defaultMode)
  }

  deinit {
    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), self.runLoopSource, .defaultMode)
  }
}