| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "services/device/battery/battery_status_manager.h" |
| |
| #import <Foundation/Foundation.h> |
| #import <UIKit/UIKit.h> |
| |
| #include <memory> |
| |
| #include "base/functional/callback.h" |
| #include "services/device/public/mojom/battery_monitor.mojom.h" |
| |
| namespace device { |
| namespace { |
| typedef BatteryStatusService::BatteryUpdateCallback BatteryCallback; |
| |
| mojom::BatteryStatus GetInternalBatteriesStates() { |
| mojom::BatteryStatus status; |
| switch ([UIDevice currentDevice].batteryState) { |
| case UIDeviceBatteryStateFull: |
| status.charging = true; |
| break; |
| case UIDeviceBatteryStateUnplugged: |
| status.charging = false; |
| break; |
| case UIDeviceBatteryStateCharging: |
| status.charging = true; |
| break; |
| case UIDeviceBatteryStateUnknown: |
| status.charging = false; |
| break; |
| } |
| if ([UIDevice currentDevice].batteryState != UIDeviceBatteryStateUnknown) { |
| status.level = [UIDevice currentDevice].batteryLevel; |
| } |
| // It's not recommended to calculate time from |
| // https://developer.apple.com/documentation/uikit/uidevicebatteryleveldidchangenotification |
| // Set `charging_time` to +Infinity if not fully charged, otherwise leave the |
| // default value, which is 0. |
| if (status.charging && status.level < 1) { |
| status.charging_time = std::numeric_limits<double>::infinity(); |
| } |
| |
| return status; |
| } |
| |
| } // namespace |
| } // namespace device |
| |
| // Starts and stops monitoring battery status. |
| @interface BatteryNotification : NSObject { |
| @private |
| device::BatteryCallback _callback; |
| } |
| - (instancetype)initWithCallback:(const device::BatteryCallback&)callback; |
| - (void)startNotification; |
| - (void)stopNotification; |
| @end |
| |
| @implementation BatteryNotification |
| - (instancetype)initWithCallback:(const device::BatteryCallback&)callback { |
| if (!(self = [super init])) { |
| return nil; |
| } |
| _callback = callback; |
| return self; |
| } |
| |
| - (void)startNotification { |
| [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES]; |
| |
| // Update the current status. |
| self->_callback.Run(device::GetInternalBatteriesStates()); |
| |
| // Add observers for battery state and level changes. |
| [[NSNotificationCenter defaultCenter] |
| addObserverForName:UIDeviceBatteryStateDidChangeNotification |
| object:nil |
| queue:[NSOperationQueue mainQueue] |
| usingBlock:^(NSNotification* notification) { |
| // BatteryState has changed. |
| self->_callback.Run(device::GetInternalBatteriesStates()); |
| }]; |
| |
| [[NSNotificationCenter defaultCenter] |
| addObserverForName:UIDeviceBatteryLevelDidChangeNotification |
| object:nil |
| queue:[NSOperationQueue mainQueue] |
| usingBlock:^(NSNotification* notification) { |
| // BatteryLevel has changed. |
| self->_callback.Run(device::GetInternalBatteriesStates()); |
| }]; |
| } |
| |
| - (void)stopNotification { |
| [[UIDevice currentDevice] setBatteryMonitoringEnabled:NO]; |
| [[NSNotificationCenter defaultCenter] |
| removeObserver:self |
| name:UIDeviceBatteryStateDidChangeNotification |
| object:nil]; |
| [[NSNotificationCenter defaultCenter] |
| removeObserver:self |
| name:UIDeviceBatteryLevelDidChangeNotification |
| object:nil]; |
| } |
| @end |
| |
| namespace device { |
| |
| namespace { |
| |
| class BatteryStatusManagerIOS : public BatteryStatusManager { |
| public: |
| explicit BatteryStatusManagerIOS(const BatteryCallback& callback) { |
| notification_ = [[BatteryNotification alloc] initWithCallback:callback]; |
| } |
| |
| BatteryStatusManagerIOS(const BatteryStatusManagerIOS&) = delete; |
| BatteryStatusManagerIOS& operator=(const BatteryStatusManagerIOS&) = delete; |
| |
| ~BatteryStatusManagerIOS() override { StopListeningBatteryChange(); } |
| |
| // BatteryStatusManager: |
| bool StartListeningBatteryChange() override { |
| [notification_ startNotification]; |
| return true; |
| } |
| |
| void StopListeningBatteryChange() override { |
| [notification_ stopNotification]; |
| } |
| |
| private: |
| __strong BatteryNotification* notification_; |
| }; |
| |
| } // namespace |
| |
| // static |
| std::unique_ptr<BatteryStatusManager> BatteryStatusManager::Create( |
| const BatteryStatusService::BatteryUpdateCallback& callback) { |
| return std::make_unique<BatteryStatusManagerIOS>(callback); |
| } |
| |
| } // namespace device |