2014 snapchat source code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

136 lines
3.8 KiB

  1. //
  2. // SCBlackCameraDetectorCameraView.m
  3. // Snapchat
  4. //
  5. // Created by Derek Wang on 24/01/2018.
  6. //
  7. #import "SCBlackCameraViewDetector.h"
  8. #import "SCBlackCameraReporter.h"
  9. #import "SCCaptureDeviceAuthorization.h"
  10. #import <SCFoundation/SCAssertWrapper.h>
  11. #import <SCFoundation/SCLog.h>
  12. #import <SCFoundation/SCQueuePerformer.h>
  13. #import <SCFoundation/SCTraceODPCompatible.h>
  14. #import <SCLogger/SCCameraMetrics.h>
  15. // Check whether we called [AVCaptureSession startRunning] within this period
  16. static CGFloat const kSCBlackCameraCheckingDelay = 0.5;
  17. @interface SCBlackCameraViewDetector () {
  18. BOOL _startRunningCalled;
  19. BOOL _sessionIsRecreating;
  20. dispatch_block_t _checkSessionBlock;
  21. }
  22. @property (nonatomic) SCQueuePerformer *queuePerformer;
  23. @property (nonatomic) SCBlackCameraReporter *reporter;
  24. @property (nonatomic, weak) UIGestureRecognizer *cameraViewGesture;
  25. @end
  26. @implementation SCBlackCameraViewDetector
  27. - (instancetype)initWithPerformer:(SCQueuePerformer *)performer reporter:(SCBlackCameraReporter *)reporter
  28. {
  29. self = [super init];
  30. if (self) {
  31. _queuePerformer = performer;
  32. _reporter = reporter;
  33. }
  34. return self;
  35. }
  36. #pragma mark - Camera view visibility change trigger
  37. - (void)onCameraViewVisible:(BOOL)visible
  38. {
  39. SCTraceODPCompatibleStart(2);
  40. SCLogCoreCameraInfo(@"[BlackCamera] onCameraViewVisible: %d", visible);
  41. BOOL firstTimeAccess = [SCCaptureDeviceAuthorization notDeterminedForVideoCapture];
  42. if (firstTimeAccess) {
  43. // We don't want to check black camera for firstTimeAccess
  44. return;
  45. }
  46. // Visible and application is active
  47. if (visible && [UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
  48. // Since this method is usually called before the view is actually visible, leave some margin to check
  49. [self _scheduleCheckDelayed:YES];
  50. } else {
  51. [_queuePerformer perform:^{
  52. if (_checkSessionBlock) {
  53. dispatch_block_cancel(_checkSessionBlock);
  54. _checkSessionBlock = nil;
  55. }
  56. }];
  57. }
  58. }
  59. // Call this when [AVCaptureSession startRunning] is called
  60. - (void)sessionWillCallStartRunning
  61. {
  62. [_queuePerformer perform:^{
  63. _startRunningCalled = YES;
  64. }];
  65. }
  66. - (void)sessionWillCallStopRunning
  67. {
  68. [_queuePerformer perform:^{
  69. _startRunningCalled = NO;
  70. }];
  71. }
  72. - (void)_scheduleCheckDelayed:(BOOL)delay
  73. {
  74. [_queuePerformer perform:^{
  75. SC_GUARD_ELSE_RETURN(!_checkSessionBlock);
  76. @weakify(self);
  77. _checkSessionBlock = dispatch_block_create(0, ^{
  78. @strongify(self);
  79. SC_GUARD_ELSE_RETURN(self);
  80. self->_checkSessionBlock = nil;
  81. [self _checkSessionState];
  82. });
  83. if (delay) {
  84. [_queuePerformer perform:_checkSessionBlock after:kSCBlackCameraCheckingDelay];
  85. } else {
  86. [_queuePerformer perform:_checkSessionBlock];
  87. }
  88. }];
  89. }
  90. - (void)_checkSessionState
  91. {
  92. SCLogCoreCameraInfo(@"[BlackCamera] checkSessionState startRunning: %d, sessionIsRecreating: %d",
  93. _startRunningCalled, _sessionIsRecreating);
  94. if (!_startRunningCalled && !_sessionIsRecreating) {
  95. [_reporter reportBlackCameraWithCause:SCBlackCameraStartRunningNotCalled];
  96. [_reporter fileShakeTicketWithCause:SCBlackCameraStartRunningNotCalled];
  97. }
  98. }
  99. - (void)sessionWillRecreate
  100. {
  101. [_queuePerformer perform:^{
  102. _sessionIsRecreating = YES;
  103. }];
  104. }
  105. - (void)sessionDidRecreate
  106. {
  107. [_queuePerformer perform:^{
  108. _sessionIsRecreating = NO;
  109. }];
  110. }
  111. - (void)onCameraViewVisibleWithTouch:(UIGestureRecognizer *)gesture
  112. {
  113. if (gesture != _cameraViewGesture) {
  114. // Skip repeating gesture
  115. self.cameraViewGesture = gesture;
  116. [self _scheduleCheckDelayed:NO];
  117. }
  118. }
  119. @end