diff --git a/Core/gb.c b/Core/gb.c index 318ab8f14..ff2953694 100644 --- a/Core/gb.c +++ b/Core/gb.c @@ -2018,6 +2018,11 @@ unsigned GB_time_to_alarm(GB_gameboy_t *gb) return alarm_time - current_time; } +bool GB_rom_supports_alarms(GB_gameboy_t *gb) +{ + return gb->cartridge_type->mbc_type == GB_HUC3; +} + bool GB_has_accelerometer(GB_gameboy_t *gb) { return gb->cartridge_type->mbc_type == GB_MBC7; diff --git a/Core/gb.h b/Core/gb.h index 377bd6bbd..d7d47ab52 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -969,6 +969,7 @@ void GB_disconnect_serial(GB_gameboy_t *gb); GB_accessory_t GB_get_built_in_accessory(GB_gameboy_t *gb); /* For cartridges with an alarm clock */ +bool GB_rom_supports_alarms(GB_gameboy_t *gb); unsigned GB_time_to_alarm(GB_gameboy_t *gb); // 0 if no alarm /* For cartridges motion controls */ diff --git a/Makefile b/Makefile index 51d31ecaf..3d7c3dfce 100644 --- a/Makefile +++ b/Makefile @@ -240,7 +240,7 @@ LDFLAGS += -arch arm64 OCFLAGS += -x objective-c -fobjc-arc -Wno-deprecated-declarations -isysroot $(SYSROOT) LDFLAGS += -miphoneos-version-min=11.0 -isysroot $(SYSROOT) REREGISTER_LDFLAGS := $(LDFLAGS) -lobjc -framework CoreServices -framework Foundation -LDFLAGS += -lobjc -framework UIKit -framework Foundation -framework CoreGraphics -framework Metal -framework MetalKit -framework AudioToolbox -framework AVFoundation -framework QuartzCore -framework CoreMotion -framework CoreVideo -framework CoreMedia -framework CoreImage -weak_framework CoreHaptics +LDFLAGS += -lobjc -framework UIKit -framework Foundation -framework CoreGraphics -framework Metal -framework MetalKit -framework AudioToolbox -framework AVFoundation -framework QuartzCore -framework CoreMotion -framework CoreVideo -framework CoreMedia -framework CoreImage -framework UserNotifications -weak_framework CoreHaptics CODESIGN := codesign -fs - else ifeq ($(PLATFORM),Darwin) diff --git a/iOS/GBViewController.h b/iOS/GBViewController.h index 133bda463..a846a8057 100644 --- a/iOS/GBViewController.h +++ b/iOS/GBViewController.h @@ -1,5 +1,6 @@ #import #import +#import typedef enum { GBRunModeNormal, @@ -8,7 +9,9 @@ typedef enum { GBRunModePaused, } GBRunMode; -@interface GBViewController : UIViewController +@interface GBViewController : UIViewController @property (nonatomic, strong) UIWindow *window; - (void)reset; - (void)openLibrary; diff --git a/iOS/GBViewController.m b/iOS/GBViewController.m index b52ebe4af..09786e780 100644 --- a/iOS/GBViewController.m +++ b/iOS/GBViewController.m @@ -244,6 +244,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( action:@selector(rotateCamera) forControlEvents:UIControlEventTouchUpInside]; [_backgroundView addSubview:_cameraPositionButton]; + + [UNUserNotificationCenter currentNotificationCenter].delegate = self; return true; } @@ -532,6 +534,18 @@ - (void)preRun GB_set_accelerometer_values(&_gb, -data.x, data.y); }]; } + + /* Clear pending alarms, don't play alarms while playing */ + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"GBNotificationsUsed"]) { + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + [center removeDeliveredNotificationsWithIdentifiers:@[[GBROMManager sharedManager].romFile]]; + [center removePendingNotificationRequestsWithIdentifiers:@[[GBROMManager sharedManager].romFile]]; + } + + if (GB_rom_supports_alarms(&_gb)) { + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + [center requestAuthorizationWithOptions:UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert completionHandler:nil]; + } } - (void)run @@ -564,6 +578,18 @@ - (void)run _stopping = false; } +- (void)userNotificationCenter:(UNUserNotificationCenter *)center +didReceiveNotificationResponse:(UNNotificationResponse *)response + withCompletionHandler:(void (^)(void))completionHandler +{ + if (![response.notification.request.identifier isEqual:[GBROMManager sharedManager].currentROM]) { + [self application:[UIApplication sharedApplication] + openURL:[NSURL fileURLWithPath:response.notification.request.identifier] + options:@{}]; + } + completionHandler(); +} + - (UIImage *)imageFromData:(NSData *)data width:(unsigned)width height:(unsigned)height { /* Convert the screenshot to a CGImageRef */ @@ -605,6 +631,30 @@ - (void)postRun [self saveStateToFile:[GBROMManager sharedManager].autosaveStateFile]; [[GBHapticManager sharedManager] setRumbleStrength:0]; [_motionManager stopAccelerometerUpdates]; + + unsigned timeToAlarm = GB_time_to_alarm(&_gb); + + if (timeToAlarm) { + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + + UNMutableNotificationContent *notificationContent = [[UNMutableNotificationContent alloc] init]; + NSString *friendlyName = [[[GBROMManager sharedManager].romFile lastPathComponent] stringByDeletingPathExtension]; + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\([^)]+\\)|\\[[^\\]]+\\]" options:0 error:nil]; + friendlyName = [regex stringByReplacingMatchesInString:friendlyName options:0 range:NSMakeRange(0, [friendlyName length]) withTemplate:@""]; + friendlyName = [friendlyName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + + notificationContent.title = [NSString stringWithFormat:@"%@ Played an Alarm", friendlyName]; + notificationContent.body = [NSString stringWithFormat:@"%@ requested your attention by playing a scheduled alarm", friendlyName]; + notificationContent.sound = UNNotificationSound.defaultSound; + + UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:[GBROMManager sharedManager].romFile + content:notificationContent + trigger:[UNTimeIntervalNotificationTrigger triggerWithTimeInterval:timeToAlarm repeats:false]]; + + + [center addNotificationRequest:request withCompletionHandler:nil]; + [[NSUserDefaults standardUserDefaults] setBool:true forKey:@"GBNotificationsUsed"]; + } } - (void)start