1// Copyright 2018-present 650 Industries. All rights reserved.
2
3#import <EXScreenCapture/EXScreenCaptureModule.h>
4
5#import <ExpoModulesCore/EXEventEmitterService.h>
6
7static NSString * const onScreenshotEventName = @"onScreenshot";
8
9@interface EXScreenCaptureModule ()
10
11@property (nonatomic, weak) EXModuleRegistry *moduleRegistry;
12@property (nonatomic, assign) BOOL isListening;
13@property (nonatomic, assign) BOOL isBeingObserved;
14@property (nonatomic, weak) id<EXEventEmitterService> eventEmitter;
15
16@end
17
18@implementation EXScreenCaptureModule {
19  UIView *_blockView;
20}
21
22EX_EXPORT_MODULE(ExpoScreenCapture);
23
24# pragma mark - EXModuleRegistryConsumer
25
26- (void)setModuleRegistry:(EXModuleRegistry *)moduleRegistry
27{
28  _moduleRegistry = moduleRegistry;
29  _eventEmitter = [moduleRegistry getModuleImplementingProtocol:@protocol(EXEventEmitterService)];
30}
31
32- (instancetype)init {
33  if (self = [super init]) {
34    CGFloat boundLength = MAX([[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height);
35    _blockView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, boundLength, boundLength)];
36    _blockView.backgroundColor = UIColor.blackColor;
37  }
38  return self;
39}
40
41# pragma mark - Exported methods
42
43EX_EXPORT_METHOD_AS(preventScreenCapture,
44                    preventScreenCaptureWithResolver:(EXPromiseResolveBlock)resolve
45                    reject:(EXPromiseRejectBlock)reject)
46{
47  // If already recording, block it
48  dispatch_async(dispatch_get_main_queue(), ^{
49    [self preventScreenRecording];
50  });
51
52  // Avoid setting duplicate observers
53  [[NSNotificationCenter defaultCenter] removeObserver:self name:UIScreenCapturedDidChangeNotification object:nil];
54
55  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(preventScreenRecording) name:UIScreenCapturedDidChangeNotification object:nil];
56
57  resolve([NSNull null]);
58}
59
60EX_EXPORT_METHOD_AS(allowScreenCapture,
61                    allowScreenCaptureWithResolver:(EXPromiseResolveBlock)resolve
62                    rejecter:(EXPromiseRejectBlock)reject)
63{
64  [[NSNotificationCenter defaultCenter] removeObserver:self name:UIScreenCapturedDidChangeNotification object:nil];
65
66  resolve([NSNull null]);
67}
68
69- (void)preventScreenRecording {
70  BOOL isCaptured = [[UIScreen mainScreen] isCaptured];
71
72  if (isCaptured) {
73    [UIApplication.sharedApplication.keyWindow.subviews.firstObject addSubview:_blockView];
74  } else {
75    [_blockView removeFromSuperview];
76  }
77}
78
79# pragma mark - EXEventEmitter
80
81- (NSArray<NSString *> *)supportedEvents
82{
83  return @[onScreenshotEventName];
84}
85
86- (void)startObserving
87{
88  [self setIsBeingObserved:YES];
89}
90
91- (void)stopObserving
92{
93  [self setIsBeingObserved:NO];
94}
95
96- (void)setIsBeingObserved:(BOOL)isBeingObserved
97{
98  _isBeingObserved = isBeingObserved;
99  BOOL shouldListen = _isBeingObserved;
100  if (shouldListen && !_isListening) {
101    // Avoid setting duplicate observers
102    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationUserDidTakeScreenshotNotification object:nil];
103    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(listenForScreenCapture) name:UIApplicationUserDidTakeScreenshotNotification object:nil];
104    _isListening = YES;
105  } else if (!shouldListen && _isListening) {
106    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationUserDidTakeScreenshotNotification object:nil];
107    _isListening = NO;
108  }
109}
110
111- (void)listenForScreenCapture
112{
113  [_eventEmitter sendEventWithName:onScreenshotEventName body:nil];
114}
115
116@end
117