Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/Battery/AppleBatteryClient.m
3187 views
1
//
2
// AppleBatteryClient.m
3
// PPSSPP
4
//
5
// Created by Serena on 24/01/2023.
6
//
7
8
#include "ppsspp_config.h"
9
10
#import <Foundation/Foundation.h>
11
12
#if PPSSPP_PLATFORM(MAC)
13
#include <IOKit/ps/IOPSKeys.h>
14
#include <IOKit/ps/IOPowerSources.h>
15
#elif PPSSPP_PLATFORM(IOS)
16
#import <UIKit/UIKit.h>
17
#endif
18
19
@interface AppleBatteryClient : NSObject
20
+(instancetype)sharedClient;
21
-(void)setNeedsToUpdateLevel;
22
@property int batteryLevel;
23
@end
24
25
void _powerSourceRunLoopCallback(void * __unused ctx) {
26
// IOKit has told us that battery information has changed, now update the batteryLevel var
27
[[AppleBatteryClient sharedClient] setNeedsToUpdateLevel];
28
}
29
30
// You may ask,
31
// "Why an entire class?
32
// Why not just call the UIDevice/IOKitPowerSource functions every time getCurrentBatteryCapacity() is called?"
33
// Well, calling the UIDevice/IOKitPowerSource functions very frequently (every second, it seems?) is expensive
34
// So, instead, I made a class with a cached batteryLevel property
35
// that only gets set when it needs to.
36
@implementation AppleBatteryClient
37
38
+ (instancetype)sharedClient {
39
static AppleBatteryClient *client;
40
static dispatch_once_t onceToken;
41
dispatch_once(&onceToken, ^{
42
client = [AppleBatteryClient new];
43
[client initialSetup];
44
[client setNeedsToUpdateLevel];
45
});
46
47
return client;
48
}
49
50
-(void)initialSetup {
51
#if TARGET_OS_IOS
52
// on iOS, this needs to be true to get the battery level
53
// and it needs to be set just once, so do it here
54
UIDevice.currentDevice.batteryMonitoringEnabled = YES;
55
// Register for when the battery % changes
56
[[NSNotificationCenter defaultCenter] addObserver:self
57
selector:@selector(setNeedsToUpdateLevel)
58
name:UIDeviceBatteryLevelDidChangeNotification object:nil];
59
60
#elif TARGET_OS_MAC
61
CFRunLoopSourceRef loop = IOPSNotificationCreateRunLoopSource(_powerSourceRunLoopCallback, nil);
62
CFRunLoopAddSource(CFRunLoopGetMain(), loop, kCFRunLoopDefaultMode);
63
#endif
64
}
65
66
- (void)setNeedsToUpdateLevel {
67
#if TARGET_OS_IOS
68
// `-[UIDevice batteryLevel]` returns the % like '0.(actual %)' (ie, 0.28 when the battery is 28%)
69
// so multiply it by 100 to get a visually appropriate version
70
self.batteryLevel = [[UIDevice currentDevice] batteryLevel] * 100;
71
#elif TARGET_OS_MAC
72
CFTypeRef snapshot = IOPSCopyPowerSourcesInfo();
73
NSArray *sourceList = (__bridge NSArray *)IOPSCopyPowerSourcesList(snapshot);
74
if (!sourceList) {
75
if (snapshot) CFRelease(snapshot);
76
return;
77
}
78
79
for (NSDictionary *source in sourceList) {
80
// kIOPSCurrentCapacityKey = battery level
81
NSNumber *currentCapacity = [source objectForKey:@(kIOPSCurrentCapacityKey)];
82
if (currentCapacity) {
83
// we found what we want
84
self.batteryLevel = currentCapacity.intValue;
85
break;
86
}
87
}
88
CFRelease(snapshot);
89
#endif
90
}
91
92
@end
93
94
// TODO: Move this.
95
int Apple_GetCurrentBatteryCapacity() {
96
return [[AppleBatteryClient sharedClient] batteryLevel];
97
}
98
99