Browse Source

Add files via upload

pull/2/head
Jonny Banana 6 years ago
committed by GitHub
parent
commit
a6140fdcf7
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 233
      Resource/SCCaptureResource.h
  2. 66
      Resource/SCCaptureResource.m
  3. 377
      Tweaks/SCCameraTweaks.h
  4. 396
      Tweaks/SCCameraTweaks.m
  5. 47
      UI/AVCameraViewEnums.h
  6. 32
      UI/Lenses/LensButtonZ/SCFeatureLensButtonZ.h
  7. 33
      UI/Lenses/LensSideButton/SCFeatureLensSideButton.h
  8. 24
      UI/SCLongPressGestureRecognizer.h
  9. 88
      UI/SCLongPressGestureRecognizer.m
  10. 31
      VolumeButton/SCCameraVolumeButtonHandler.h
  11. 190
      VolumeButton/SCCameraVolumeButtonHandler.m
  12. 109
      Worker/SCCaptureWorker.h
  13. 1095
      Worker/SCCaptureWorker.m

233
Resource/SCCaptureResource.h

@ -0,0 +1,233 @@
//
// SCCaptureResource.h
// Snapchat
//
// Created by Lin Jia on 10/19/17.
//
//
#import "SCManagedCapturerLensAPI.h"
#import "SCManagedCapturerListenerAnnouncer.h"
#import "SCSnapCreationTriggers.h"
#import <SCCameraFoundation/SCManagedVideoDataSource.h>
#import <FBKVOController/FBKVOController.h>
#import <Foundation/Foundation.h>
/*
In general, the function of SCCapturer is to use some resources (such as SCManagedCapturerListenerAnnouncer), to do
something (such as announce an event).
SCCaptureResource abstract away the "resources" part of SCCapturer. It has no APIs itself, it is used to be the
resource which gets passed arround for capturer V2 state machine.
*/
@class SCManagedDeviceCapacityAnalyzer;
@class SCManagedCapturePreviewLayerController;
@class ARSession;
@class SCManagedVideoScanner;
@class LSAGLView;
@protocol SCManagedCapturerLSAComponentTrackerAPI;
@class SCManagedStillImageCapturer;
@class SCManagedVideoCapturer;
@class SCQueuePerformer;
@class SCManagedVideoFrameSampler;
@class SCManagedDroppedFramesReporter;
@class SCManagedVideoStreamReporter;
@protocol SCManagedCapturerGLViewManagerAPI;
@class SCCapturerToken;
@class SCSingleFrameStreamCapturer;
@class SCManagedFrontFlashController;
@class SCManagedVideoCapturerHandler;
@class SCManagedStillImageCapturerHandler;
@class SCManagedDeviceCapacityAnalyzerHandler;
@class SCManagedCaptureDeviceDefaultZoomHandler;
@class SCManagedCaptureDeviceHandler;
@class SCBlackCameraNoOutputDetector;
@class SCCaptureSessionFixer;
@protocol SCCaptureFaceDetector;
@protocol SCManagedCapturerLensAPI;
@protocol SCManagedCapturerARImageCaptureProvider;
@class SCManagedCapturerARSessionHandler;
@class SCManagedCaptureDeviceSubjectAreaHandler;
@class SCManagedCaptureSession;
@class SCBlackCameraDetector;
@protocol SCLensProcessingCore;
@protocol SCManagedCapturerLensAPI;
@protocol SCManagedCapturePreviewLayerControllerDelegate;
typedef enum : NSUInteger {
SCManagedCapturerStatusUnknown = 0,
SCManagedCapturerStatusReady,
SCManagedCapturerStatusRunning,
} SCManagedCapturerStatus;
@protocol SCDeviceMotionProvider
@property (nonatomic, readonly) BOOL isUnderDeviceMotion;
@end
@protocol SCFileInputDecider
@property (nonatomic, readonly) BOOL shouldProcessFileInput;
@property (nonatomic, readonly) NSURL *fileURL;
@end
@interface SCCaptureResource : NSObject
@property (nonatomic, readwrite, assign) SCManagedCapturerStatus status;
@property (nonatomic, readwrite, strong) SCManagedCapturerState *state;
@property (nonatomic, readwrite, strong) SCManagedCaptureDevice *device;
@property (nonatomic, readwrite, strong) id<SCManagedCapturerLensAPI> lensProcessingCore;
@property (nonatomic, readwrite, strong) id<SCManagedCapturerLensAPIProvider> lensAPIProvider;
@property (nonatomic, readwrite, strong) ARSession *arSession NS_AVAILABLE_IOS(11_0);
@property (nonatomic, readwrite, strong) SCManagedStillImageCapturer *arImageCapturer NS_AVAILABLE_IOS(11_0);
@property (nonatomic, readwrite, strong) SCManagedCaptureSession *managedSession;
@property (nonatomic, readwrite, strong) id<SCManagedVideoDataSource> videoDataSource;
@property (nonatomic, readwrite, strong) SCManagedDeviceCapacityAnalyzer *deviceCapacityAnalyzer;
@property (nonatomic, readwrite, strong) SCManagedVideoScanner *videoScanner;
@property (nonatomic, readwrite, strong) SCManagedCapturerListenerAnnouncer *announcer;
@property (nonatomic, readwrite, strong) AVCaptureVideoPreviewLayer *videoPreviewLayer;
@property (nonatomic, readwrite, strong) id<SCManagedCapturerGLViewManagerAPI> videoPreviewGLViewManager;
@property (nonatomic, readwrite, strong) SCManagedStillImageCapturer *stillImageCapturer;
@property (nonatomic, readwrite, strong) SCManagedVideoCapturer *videoCapturer;
@property (nonatomic, readwrite, strong) SCQueuePerformer *queuePerformer;
@property (nonatomic, readwrite, strong) SCManagedVideoFrameSampler *videoFrameSampler;
@property (nonatomic, readwrite, strong) SCManagedDroppedFramesReporter *droppedFramesReporter;
@property (nonatomic, readwrite, strong) SCManagedVideoStreamReporter *videoStreamReporter; // INTERNAL USE ONLY
@property (nonatomic, readwrite, strong) SCManagedFrontFlashController *frontFlashController;
@property (nonatomic, readwrite, strong) SCManagedVideoCapturerHandler *videoCapturerHandler;
@property (nonatomic, readwrite, strong) SCManagedStillImageCapturerHandler *stillImageCapturerHandler;
@property (nonatomic, readwrite, strong) SCManagedDeviceCapacityAnalyzerHandler *deviceCapacityAnalyzerHandler;
@property (nonatomic, readwrite, strong) SCManagedCaptureDeviceDefaultZoomHandler *deviceZoomHandler;
@property (nonatomic, readwrite, strong) SCManagedCaptureDeviceHandler *captureDeviceHandler;
@property (nonatomic, readwrite, strong) id<SCCaptureFaceDetector> captureFaceDetector;
@property (nonatomic, readwrite, strong) FBKVOController *kvoController;
@property (nonatomic, readwrite, strong) id<SCManagedCapturerLSAComponentTrackerAPI> lsaTrackingComponentHandler;
@property (nonatomic, readwrite, strong) SCManagedCapturerARSessionHandler *arSessionHandler;
@property (nonatomic, assign) SEL completeARSessionShutdown;
@property (nonatomic, assign) SEL handleAVSessionStatusChange;
@property (nonatomic, assign) BOOL videoRecording;
@property (nonatomic, assign) NSInteger numRetriesFixAVCaptureSessionWithCurrentSession;
@property (nonatomic, assign) BOOL appInBackground;
@property (nonatomic, assign) NSUInteger streamingSequence;
@property (nonatomic, assign) BOOL stillImageCapturing;
@property (nonatomic, readwrite, strong) NSTimer *livenessTimer;
@property (nonatomic, readwrite, strong) NSMutableSet<SCCapturerToken *> *tokenSet;
@property (nonatomic, readwrite, strong) SCSingleFrameStreamCapturer *frameCap;
@property (nonatomic, readwrite, strong) id<SCManagedSampleBufferDisplayController> sampleBufferDisplayController;
@property (nonatomic, readwrite, strong) SCSnapCreationTriggers *snapCreationTriggers;
// Different from most properties above, following are main thread properties.
@property (nonatomic, assign) BOOL allowsZoom;
@property (nonatomic, assign) NSUInteger numRetriesFixInconsistencyWithCurrentSession;
@property (nonatomic, readwrite, strong) NSMutableDictionary *debugInfoDict;
@property (nonatomic, assign) BOOL notificationRegistered;
@property (nonatomic, readwrite, strong) SCManagedCaptureDeviceSubjectAreaHandler *deviceSubjectAreaHandler;
@property (nonatomic, assign) SEL sessionRuntimeError;
@property (nonatomic, assign) SEL livenessConsistency;
// TODO: these properties will be refactored into SCCaptureSessionFixer class
// The refactor will be in a separate PR
// Timestamp when _fixAVSessionIfNecessary is called
@property (nonatomic, assign) NSTimeInterval lastFixSessionTimestamp;
// Timestamp when session runtime error is handled
@property (nonatomic, assign) NSTimeInterval lastSessionRuntimeErrorTime;
// Wether we schedule fix of creating session already
@property (nonatomic, assign) BOOL isRecreateSessionFixScheduled;
@property (nonatomic, readwrite, strong) SCCaptureSessionFixer *captureSessionFixer;
@property (nonatomic, readwrite, strong) SCBlackCameraDetector *blackCameraDetector;
@property (nonatomic, readwrite, strong) id<SCDeviceMotionProvider> deviceMotionProvider;
@property (nonatomic, readwrite, strong) id<SCManagedCapturerARImageCaptureProvider> arImageCaptureProvider;
@property (nonatomic, readwrite, strong) id<SCFileInputDecider> fileInputDecider;
@property (nonatomic, readwrite, strong)
id<SCManagedCapturePreviewLayerControllerDelegate> previewLayerControllerDelegate;
@end

66
Resource/SCCaptureResource.m

@ -0,0 +1,66 @@
//
// SCCaptureResource.m
// Snapchat
//
// Created by Lin Jia on 10/19/17.
//
//
#import "SCCaptureResource.h"
#import "SCBlackCameraDetector.h"
#import "SCManagedCapturerState.h"
#import "SCManagedFrontFlashController.h"
#import "SCManagedVideoCapturer.h"
#import <SCFoundation/SCAssertWrapper.h>
#import <SCFoundation/SCQueuePerformer.h>
#import <SCFoundation/SCTraceODPCompatible.h>
#import <FBKVOController/FBKVOController.h>
@interface SCCaptureResource () {
FBKVOController *_previewHiddenKVO;
}
@end
@implementation SCCaptureResource
- (SCManagedFrontFlashController *)frontFlashController
{
SCTraceODPCompatibleStart(2);
SCAssert([self.queuePerformer isCurrentPerformer], @"");
if (!_frontFlashController) {
_frontFlashController = [[SCManagedFrontFlashController alloc] init];
}
return _frontFlashController;
}
- (void)setVideoPreviewLayer:(AVCaptureVideoPreviewLayer *)layer
{
SC_GUARD_ELSE_RETURN(layer != _videoPreviewLayer);
if (_videoPreviewLayer) {
[_previewHiddenKVO unobserve:_videoPreviewLayer];
}
_videoPreviewLayer = layer;
SC_GUARD_ELSE_RETURN(_videoPreviewLayer);
if (!_previewHiddenKVO) {
_previewHiddenKVO = [[FBKVOController alloc] initWithObserver:self];
}
[_previewHiddenKVO observe:_videoPreviewLayer
keyPath:@keypath(_videoPreviewLayer.hidden)
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
block:^(id observer, id object, NSDictionary *change) {
BOOL oldValue = [change[NSKeyValueChangeOldKey] boolValue];
BOOL newValue = [change[NSKeyValueChangeNewKey] boolValue];
if (oldValue != newValue) {
[_blackCameraDetector capturePreviewDidBecomeVisible:!newValue];
}
}];
}
@end

377
Tweaks/SCCameraTweaks.h

@ -0,0 +1,377 @@
//
// SCCameraTweaks.h
// Snapchat
//
// Created by Liu Liu on 9/16/15.
// Copyright © 2015 Snapchat, Inc. All rights reserved.
//
#import <SCBase/SCMacros.h>
#import <SCCameraFoundation/SCManagedCaptureDevicePosition.h>
#import <SCTweakAdditions/SCTweakDefines.h>
#import <Tweaks/FBTweakInline.h>
#import <CoreGraphics/CoreGraphics.h>
#import <Foundation/Foundation.h>
// Core Camera
typedef NS_ENUM(NSUInteger, SCManagedCaptureDeviceZoomHandlerType) {
SCManagedCaptureDeviceDefaultZoom,
SCManagedCaptureDeviceSavitzkyGolayFilter,
SCManagedCaptureDeviceLinearInterpolation,
};
typedef NS_ENUM(NSUInteger, SCCameraTweaksStrategyType) {
SCCameraTweaksStrategyFollowABTest = 0,
SCCameraTweaksStrategyOverrideToYes,
SCCameraTweaksStrategyOverrideToNo
};
typedef NS_ENUM(NSUInteger, SCCameraHandsFreeModeType) {
SCCameraHandsFreeModeTypeABTest = 0,
SCCameraHandsFreeModeTypeDisabled,
SCCameraHandsFreeModeTypeMainOnly,
SCCameraHandsFreeModeTypeChatMoveCaptureButton,
SCCameraHandsFreeModeTypeMainAndChat,
SCCameraHandsFreeModeTypeLeftOfCapture,
};
/// Face detection and focus strategy in Tweak. There are less options in internal Tweaks than the A/B testing
/// strategies.
typedef NS_ENUM(NSUInteger, SCCameraFaceFocusModeStrategyType) {
SCCameraFaceFocusModeStrategyTypeABTest = 0,
SCCameraFaceFocusModeStrategyTypeDisabled, // Disabled for both cameras.
SCCameraFaceFocusModeStrategyTypeOffByDefault, // Enabled for both cameras, but is off by default.
SCCameraFaceFocusModeStrategyTypeOnByDefault, // Enabled for both cameras, but is off by default.
};
typedef NS_ENUM(NSUInteger, SCCameraFaceFocusDetectionMethodType) {
SCCameraFaceFocusDetectionMethodTypeABTest = 0,
SCCameraFaceFocusDetectionMethodTypeCIDetector, // Use SCCaptureCoreImageFaceDetector
SCCameraFaceFocusDetectionMethodTypeAVMetadata, // Use SCCaptureMetadataOutputDetector
};
SC_EXTERN_C_BEGIN
extern SCManagedCaptureDeviceZoomHandlerType SCCameraTweaksDeviceZoomHandlerStrategy(void);
extern BOOL SCCameraTweaksBlackCameraRecoveryEnabled(void);
extern BOOL SCCameraTweaksMicPermissionEnabled(void);
extern BOOL SCCameraTweaksEnableCaptureKeepRecordedVideo(void);
extern BOOL SCCameraTweaksEnableHandsFreeXToCancel(void);
extern SCCameraHandsFreeModeType SCCameraTweaksHandsFreeMode(void);
BOOL SCCameraTweaksEnableShortPreviewTransitionAnimationDuration(void);
extern BOOL SCCameraTweaksEnablePreviewPresenterFastPreview(void);
extern BOOL SCCameraTweaksEnableCaptureSharePerformer(void);
extern BOOL SCCameraTweaksEnableFaceDetectionFocus(SCManagedCaptureDevicePosition captureDevicePosition);
extern BOOL SCCameraTweaksTurnOnFaceDetectionFocusByDefault(SCManagedCaptureDevicePosition captureDevicePosition);
extern SCCameraFaceFocusDetectionMethodType SCCameraFaceFocusDetectionMethod(void);
extern CGFloat SCCameraFaceFocusMinFaceSize(void);
extern BOOL SCCameraTweaksSessionLightWeightFixEnabled(void);
SC_EXTERN_C_END
static inline BOOL SCCameraTweaksEnableVideoStabilization(void)
{
return FBTweakValue(@"Camera", @"Core Camera", @"Enable video stabilization", NO);
}
static inline BOOL SCCameraTweaksEnableForceTouchToToggleCamera(void)
{
return FBTweakValue(@"Camera", @"Recording", @"Force Touch to Toggle", NO);
}
static inline BOOL SCCameraTweaksEnableStayOnCameraAfterPostingStory(void)
{
return FBTweakValue(@"Camera", @"Story", @"Stay on camera after posting", NO);
}
static inline BOOL SCCameraTweaksEnableKeepLastFrameOnCamera(void)
{
return FBTweakValue(@"Camera", @"Core Camera", @"Keep last frame on camera", YES);
}
static inline BOOL SCCameraTweaksSmoothAutoFocusWhileRecording(void)
{
return FBTweakValue(@"Camera", @"Core Camera", @"Smooth autofocus while recording", YES);
}
static inline NSInteger SCCameraExposureAdjustmentMode(void)
{
return [FBTweakValue(
@"Camera", @"Core Camera", @"Adjust Exposure", (id) @0,
(@{ @0 : @"NO",
@1 : @"Dynamic enhancement",
@2 : @"Night vision",
@3 : @"Inverted night vision" })) integerValue];
}
static inline BOOL SCCameraTweaksRotateToggleCameraButton(void)
{
return SCTweakValueWithHalt(@"Camera", @"Core Camera", @"Rotate Toggle-Camera Button", NO);
}
static inline CGFloat SCCameraTweaksRotateToggleCameraButtonTime(void)
{
return FBTweakValue(@"Camera", @"Core Camera", @"Toggle-Camera Button Rotation Time", 0.3);
}
static inline BOOL SCCameraTweaksDefaultPortrait(void)
{
return FBTweakValue(@"Camera", @"Core Camera", @"Default to Portrait Orientation", YES);
}
// For test purpose
static inline BOOL SCCameraTweaksTranscodingAlwaysFails(void)
{
return FBTweakValue(@"Camera", @"Core Camera", @"Transcoding always fails", NO);
}
// This tweak disables the video masking behavior of the snap overlays;
// Intended to be used by curators who are on-site snapping special events.
// Ping news-dev@snapchat.com for any questions/comments
static inline BOOL SCCameraTweaksDisableOverlayVideoMask(void)
{
return FBTweakValue(@"Camera", @"Creative Tools", @"Disable Overlay Video Masking", NO);
}
static inline NSInteger SCCameraTweaksDelayTurnOnFilters(void)
{
return [FBTweakValue(@"Camera", @"Core Camera", @"Delay turn on filter", (id) @0,
(@{ @0 : @"Respect A/B testing",
@1 : @"Override to YES",
@2 : @"Override to NO" })) integerValue];
}
static inline BOOL SCCameraTweaksEnableExposurePointObservation(void)
{
return FBTweakValue(@"Camera", @"Core Camera - Face Focus", @"Observe Exposure Point", NO);
}
static inline BOOL SCCameraTweaksEnableFocusPointObservation(void)
{
return FBTweakValue(@"Camera", @"Core Camera - Face Focus", @"Observe Focus Point", NO);
}
static inline CGFloat SCCameraTweaksSmoothZoomThresholdTime()
{
return FBTweakValue(@"Camera", @"Zoom Strategy - Linear Interpolation", @"Threshold time", 0.3);
}
static inline CGFloat SCCameraTweaksSmoothZoomThresholdFactor()
{
return FBTweakValue(@"Camera", @"Zoom Strategy - Linear Interpolation", @"Threshold factor diff", 0.25);
}
static inline CGFloat SCCameraTweaksSmoothZoomIntermediateFramesPerSecond()
{
return FBTweakValue(@"Camera", @"Zoom Strategy - Linear Interpolation", @"Intermediate fps", 60);
}
static inline CGFloat SCCameraTweaksSmoothZoomDelayTolerantTime()
{
return FBTweakValue(@"Camera", @"Zoom Strategy - Linear Interpolation", @"Delay tolerant time", 0.15);
}
static inline CGFloat SCCameraTweaksSmoothZoomMinStepLength()
{
return FBTweakValue(@"Camera", @"Zoom Strategy - Linear Interpolation", @"Min step length", 0.05);
}
static inline CGFloat SCCameraTweaksExposureDeadline()
{
return FBTweakValue(@"Camera", @"Adjust Exposure", @"Exposure Deadline", 0.2);
}
static inline BOOL SCCameraTweaksKillFrontCamera(void)
{
return SCTweakValueWithHalt(@"Camera", @"Debugging", @"Kill Front Camera", NO);
}
static inline BOOL SCCameraTweaksKillBackCamera(void)
{
return SCTweakValueWithHalt(@"Camera", @"Debugging", @"Kill Back Camera", NO);
}
#if TARGET_IPHONE_SIMULATOR
static inline BOOL SCCameraTweaksUseRealMockImage(void)
{
return FBTweakValue(@"Camera", @"Debugging", @"Use real mock image on simulator", YES);
}
#endif
static inline CGFloat SCCameraTweaksShortPreviewTransitionAnimationDuration()
{
return FBTweakValue(@"Camera", @"Preview Transition", @"Short Animation Duration", 0.35);
}
static inline SCCameraTweaksStrategyType SCCameraTweaksPreviewTransitionAnimationDurationStrategy()
{
NSNumber *strategy = SCTweakValueWithHalt(@"Camera", @"Preview Transition", @"Enable Short Animation Duration",
(id) @(SCCameraTweaksStrategyFollowABTest), (@{
@(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing",
@(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES",
@(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO"
}));
return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue];
}
static inline CGFloat SCCameraTweaksEnablePortraitModeButton(void)
{
return FBTweakValue(@"Camera", @"Core Camera - Portrait Mode", @"Enable Button", NO);
}
static inline CGFloat SCCameraTweaksDepthBlurForegroundThreshold(void)
{
return FBTweakValue(@"Camera", @"Core Camera - Portrait Mode", @"Foreground Blur Threshold", 0.3);
}
static inline CGFloat SCCameraTweaksDepthBlurBackgroundThreshold(void)
{
return FBTweakValue(@"Camera", @"Core Camera - Portrait Mode", @"Background Blur Threshold", 0.1);
}
static inline CGFloat SCCameraTweaksBlurSigma(void)
{
return FBTweakValue(@"Camera", @"Core Camera - Portrait Mode", @"Blur Sigma", 4.0);
}
static inline BOOL SCCameraTweaksEnableFilterInputFocusRect(void)
{
return FBTweakValue(@"Camera", @"Core Camera - Portrait Mode", @"Filter Input Focus Rect", NO);
}
static inline BOOL SCCameraTweaksEnablePortraitModeTapToFocus(void)
{
return FBTweakValue(@"Camera", @"Core Camera - Portrait Mode", @"Tap to Focus", NO);
}
static inline BOOL SCCameraTweaksEnablePortraitModeAutofocus(void)
{
return FBTweakValue(@"Camera", @"Core Camera - Portrait Mode", @"Autofocus", NO);
}
static inline BOOL SCCameraTweaksDepthToGrayscaleOverride(void)
{
return FBTweakValue(@"Camera", @"Core Camera - Portrait Mode", @"Depth to Grayscale Override", NO);
}
static inline SCCameraTweaksStrategyType SCCameraTweaksEnableHandsFreeXToCancelStrategy(void)
{
NSNumber *strategy = SCTweakValueWithHalt(@"Camera", @"Hands-Free Recording", @"X to Cancel",
(id) @(SCCameraTweaksStrategyFollowABTest), (@{
@(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing",
@(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES",
@(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO"
}));
return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue];
}
static inline SCCameraHandsFreeModeType SCCameraTweaksHandsFreeModeType()
{
NSNumber *strategy = SCTweakValueWithHalt(
@"Camera", @"Hands-Free Recording", @"Enabled", (id) @(SCCameraHandsFreeModeTypeABTest), (@{
@(SCCameraHandsFreeModeTypeABTest) : @"Respect A/B testing",
@(SCCameraHandsFreeModeTypeDisabled) : @"Disable",
@(SCCameraHandsFreeModeTypeMainOnly) : @"Main Camera only",
@(SCCameraHandsFreeModeTypeChatMoveCaptureButton) : @"Main Camera + move Chat capture button",
@(SCCameraHandsFreeModeTypeMainAndChat) : @"Main + Chat Cameras",
@(SCCameraHandsFreeModeTypeLeftOfCapture) : @"Left of Main + Chat Cameras"
}));
return (SCCameraHandsFreeModeType)[strategy unsignedIntegerValue];
}
static inline SCCameraTweaksStrategyType SCCameraTweaksPreviewPresenterFastPreviewStrategy(void)
{
NSNumber *strategy = SCTweakValueWithHalt(@"Camera", @"Preview Presenter", @"Fast Preview",
(id) @(SCCameraTweaksStrategyFollowABTest), (@{
@(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing",
@(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES",
@(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO"
}));
return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue];
}
static inline NSInteger SCCameraTweaksEnableCaptureKeepRecordedVideoStrategy(void)
{
NSNumber *strategy =
SCTweakValueWithHalt(@"Camera", @"Core Camera - Capture Keep Recorded Video",
@"Enable Capture Keep Recorded Video", (id) @(SCCameraTweaksStrategyFollowABTest), (@{
@(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing",
@(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES",
@(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO"
}));
return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue];
}
static inline NSInteger SCCameraTweaksEnableCaptureSharePerformerStrategy(void)
{
NSNumber *strategy =
SCTweakValueWithHalt(@"Camera", @"Core Camera - Capture Share Performer", @"Enable Capture Share Performer",
(id) @(SCCameraTweaksStrategyFollowABTest), (@{
@(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing",
@(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES",
@(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO"
}));
return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue];
}
static inline SCCameraFaceFocusModeStrategyType SCCameraTweaksFaceFocusStrategy()
{
NSNumber *strategy =
SCTweakValueWithHalt(@"Camera", @"Core Camera - Face Focus", @"Enable Face Focus",
(id) @(SCCameraFaceFocusModeStrategyTypeABTest), (@{
@(SCCameraFaceFocusModeStrategyTypeABTest) : @"Respect A/B testing",
@(SCCameraFaceFocusModeStrategyTypeDisabled) : @"Disabled",
@(SCCameraFaceFocusModeStrategyTypeOffByDefault) : @"Enabled, off by default",
@(SCCameraFaceFocusModeStrategyTypeOnByDefault) : @"Enabled, on by default",
}));
return (SCCameraFaceFocusModeStrategyType)[strategy unsignedIntegerValue];
}
static inline SCCameraFaceFocusDetectionMethodType SCCameraTweaksFaceFocusDetectionMethodType()
{
NSNumber *strategy =
SCTweakValueWithHalt(@"Camera", @"Core Camera - Face Focus", @"Detection Method",
(id) @(SCCameraFaceFocusDetectionMethodTypeABTest), (@{
@(SCCameraFaceFocusDetectionMethodTypeABTest) : @"Respect A/B testing",
@(SCCameraFaceFocusDetectionMethodTypeCIDetector) : @"CIDetector",
@(SCCameraFaceFocusDetectionMethodTypeAVMetadata) : @"AVMetadata",
}));
return (SCCameraFaceFocusDetectionMethodType)[strategy unsignedIntegerValue];
}
static inline int SCCameraTweaksFaceFocusDetectionFrequency()
{
return FBTweakValue(@"Camera", @"Core Camera - Face Focus", @"Detection Frequency", 3, 1, 30);
}
static inline BOOL SCCameraTweaksFaceFocusMinFaceSizeRespectABTesting()
{
return SCTweakValueWithHalt(@"Camera", @"Core Camera - Face Focus", @"Min Face Size Respect AB", YES);
}
static inline CGFloat SCCameraTweaksFaceFocusMinFaceSizeValue()
{
return FBTweakValue(@"Camera", @"Core Camera - Face Focus", @"Min Face Size", 0.25, 0.01, 0.5);
}
static inline BOOL SCCameraTweaksEnableDualCamera(void)
{
return SCTweakValueWithHalt(@"Camera", @"Core Camera - Dual Camera", @"Enable Dual Camera", NO);
}

396
Tweaks/SCCameraTweaks.m

@ -0,0 +1,396 @@
//
// SCCameraTweaks.m
// Snapchat
//
// Created by Liu Liu on 10/4/16.
// Copyright © 2016 Snapchat, Inc. All rights reserved.
//
#import "SCCameraTweaks.h"
#import "SCManagedCapturePreviewLayerController.h"
#import <SCFoundation/SCDeviceName.h>
#import <SCFoundation/SCZeroDependencyExperiments.h>
#import <SCTweakAdditions/SCTweakDefines.h>
SCManagedCaptureDeviceZoomHandlerType SCCameraTweaksDeviceZoomHandlerStrategy(void)
{
NSNumber *strategyNumber = SCTweakValueWithHalt(
@"Camera", @"Core Camera", @"Zoom Strategy",
@(SCIsMasterBuild() ? SCManagedCaptureDeviceLinearInterpolation : SCManagedCaptureDeviceDefaultZoom), (@{
@(SCManagedCaptureDeviceDefaultZoom) : @"Default",
@(SCManagedCaptureDeviceSavitzkyGolayFilter) : @"Savitzky-Golay Filter",
@(SCManagedCaptureDeviceLinearInterpolation) : @"Linear Interpolation"
}));
return (SCManagedCaptureDeviceZoomHandlerType)[strategyNumber integerValue];
}
BOOL SCCameraTweaksEnableFaceDetectionFocus(SCManagedCaptureDevicePosition captureDevicePosition)
{
SC_GUARD_ELSE_RETURN_VALUE([SCDeviceName isIphone], NO);
SC_GUARD_ELSE_RETURN_VALUE(captureDevicePosition != SCManagedCaptureDevicePositionBackDualCamera, NO);
BOOL isFrontCamera = (captureDevicePosition == SCManagedCaptureDevicePositionFront);
BOOL isEnabled = NO;
SCCameraFaceFocusModeStrategyType option = SCCameraTweaksFaceFocusStrategy();
switch (option) {
case SCCameraFaceFocusModeStrategyTypeABTest:
if (isFrontCamera) {
isEnabled = SCExperimentWithFaceDetectionFocusFrontCameraEnabled();
} else {
isEnabled = SCExperimentWithFaceDetectionFocusBackCameraEnabled();
}
break;
case SCCameraFaceFocusModeStrategyTypeDisabled:
isEnabled = NO;
break;
case SCCameraFaceFocusModeStrategyTypeOffByDefault:
case SCCameraFaceFocusModeStrategyTypeOnByDefault:
isEnabled = YES;
break;
}
return isEnabled;
}
BOOL SCCameraTweaksTurnOnFaceDetectionFocusByDefault(SCManagedCaptureDevicePosition captureDevicePosition)
{
SC_GUARD_ELSE_RETURN_VALUE([SCDeviceName isIphone], NO);
SC_GUARD_ELSE_RETURN_VALUE(captureDevicePosition != SCManagedCaptureDevicePositionBackDualCamera, NO);
BOOL isFrontCamera = (captureDevicePosition == SCManagedCaptureDevicePositionFront);
BOOL isOnByDefault = NO;
SCCameraFaceFocusModeStrategyType option = SCCameraTweaksFaceFocusStrategy();
switch (option) {
case SCCameraFaceFocusModeStrategyTypeABTest:
if (isFrontCamera) {
isOnByDefault = SCExperimentWithFaceDetectionFocusFrontCameraOnByDefault();
} else {
isOnByDefault = SCExperimentWithFaceDetectionFocusBackCameraOnByDefault();
}
break;
case SCCameraFaceFocusModeStrategyTypeDisabled:
case SCCameraFaceFocusModeStrategyTypeOffByDefault:
isOnByDefault = NO;
break;
case SCCameraFaceFocusModeStrategyTypeOnByDefault:
isOnByDefault = YES;
break;
}
return isOnByDefault;
}
SCCameraFaceFocusDetectionMethodType SCCameraFaceFocusDetectionMethod()
{
static SCCameraFaceFocusDetectionMethodType detectionMethodType;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SCCameraFaceFocusDetectionMethodType option = SCCameraTweaksFaceFocusDetectionMethodType();
switch (option) {
case SCCameraFaceFocusDetectionMethodTypeABTest: {
// Check the validity of AB value.
NSUInteger experimentValue = SCExperimentWithFaceDetectionFocusDetectionMethod();
if (experimentValue >= SCCameraFaceFocusDetectionMethodTypeCIDetector &&
experimentValue <= SCCameraFaceFocusDetectionMethodTypeAVMetadata) {
detectionMethodType = experimentValue;
} else {
// Use CIDetector by default.
detectionMethodType = SCCameraFaceFocusDetectionMethodTypeCIDetector;
}
} break;
case SCCameraFaceFocusDetectionMethodTypeAVMetadata:
detectionMethodType = SCCameraFaceFocusDetectionMethodTypeAVMetadata;
break;
case SCCameraFaceFocusDetectionMethodTypeCIDetector:
detectionMethodType = SCCameraFaceFocusDetectionMethodTypeCIDetector;
break;
}
});
return detectionMethodType;
}
CGFloat SCCameraFaceFocusMinFaceSize(void)
{
static CGFloat minFaceSize;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (SCCameraTweaksFaceFocusMinFaceSizeRespectABTesting()) {
minFaceSize = (CGFloat)SCExperimentWithFaceDetectionMinFaceSize();
} else {
minFaceSize = SCCameraTweaksFaceFocusMinFaceSizeValue();
}
if (minFaceSize < 0.01 || minFaceSize > 0.5) {
minFaceSize = 0.25; // Default value is 0.25
}
});
return minFaceSize;
}
BOOL SCCameraTweaksEnableCaptureKeepRecordedVideo(void)
{
static BOOL enableCaptureKeepRecordedVideo;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
switch (SCCameraTweaksEnableCaptureKeepRecordedVideoStrategy()) {
case SCCameraTweaksStrategyOverrideToYes: {
enableCaptureKeepRecordedVideo = YES;
break;
}
case SCCameraTweaksStrategyOverrideToNo: {
enableCaptureKeepRecordedVideo = NO;
break;
}
case SCCameraTweaksStrategyFollowABTest: {
enableCaptureKeepRecordedVideo = SCExperimentWithCaptureKeepRecordedVideo();
break;
}
default: {
enableCaptureKeepRecordedVideo = NO;
break;
}
}
});
return enableCaptureKeepRecordedVideo;
}
static inline SCCameraTweaksStrategyType SCCameraTweaksBlackCameraRecoveryStrategy(void)
{
NSNumber *strategy = SCTweakValueWithHalt(@"Camera", @"Core Camera", @"Black Camera Recovery",
(id) @(SCCameraTweaksStrategyFollowABTest), (@{
@(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing",
@(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES",
@(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO"
}));
return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue];
}
BOOL SCCameraTweaksBlackCameraRecoveryEnabled(void)
{
static BOOL enabled;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
switch (SCCameraTweaksBlackCameraRecoveryStrategy()) {
case SCCameraTweaksStrategyOverrideToYes:
enabled = YES;
break;
case SCCameraTweaksStrategyOverrideToNo:
enabled = NO;
break;
case SCCameraTweaksStrategyFollowABTest:
enabled = SCExperimentWithBlackCameraRecovery();
break;
default:
enabled = NO;
break;
}
});
return enabled;
}
static inline SCCameraTweaksStrategyType SCCameraTweaksMicrophoneNotificationStrategy(void)
{
NSNumber *strategy = SCTweakValueWithHalt(@"Camera", @"Core Camera", @"Mic Notification",
(id) @(SCCameraTweaksStrategyFollowABTest), (@{
@(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing",
@(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES",
@(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO"
}));
return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue];
}
BOOL SCCameraTweaksMicPermissionEnabled(void)
{
static BOOL enabled;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
switch (SCCameraTweaksMicrophoneNotificationStrategy()) {
case SCCameraTweaksStrategyOverrideToYes:
enabled = YES;
break;
case SCCameraTweaksStrategyOverrideToNo:
enabled = NO;
break;
case SCCameraTweaksStrategyFollowABTest:
enabled = SCExperimentWithMicrophonePermissionNotificationEnabled();
break;
default:
enabled = NO;
break;
}
});
return enabled;
}
SCCameraHandsFreeModeType SCCameraTweaksHandsFreeMode(void)
{
static SCCameraHandsFreeModeType handsFreeModeType;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SCCameraHandsFreeModeType option = SCCameraTweaksHandsFreeModeType();
switch (option) {
case SCCameraHandsFreeModeTypeDisabled:
handsFreeModeType = SCCameraHandsFreeModeTypeDisabled;
break;
case SCCameraHandsFreeModeTypeMainOnly:
handsFreeModeType = SCCameraHandsFreeModeTypeMainOnly;
break;
case SCCameraHandsFreeModeTypeChatMoveCaptureButton:
handsFreeModeType = SCCameraHandsFreeModeTypeChatMoveCaptureButton;
break;
case SCCameraHandsFreeModeTypeMainAndChat:
handsFreeModeType = SCCameraHandsFreeModeTypeMainAndChat;
break;
case SCCameraHandsFreeModeTypeLeftOfCapture:
handsFreeModeType = SCCameraHandsFreeModeTypeLeftOfCapture;
break;
case SCCameraHandsFreeModeTypeABTest:
default:
handsFreeModeType = SCExperimentWithHandsFreeMode();
break;
}
});
return handsFreeModeType;
}
BOOL SCCameraTweaksEnableHandsFreeXToCancel(void)
{
static BOOL enableHandsFreeXToCancel;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
switch (SCCameraTweaksEnableHandsFreeXToCancelStrategy()) {
case SCCameraTweaksStrategyOverrideToYes: {
enableHandsFreeXToCancel = YES;
break;
}
case SCCameraTweaksStrategyOverrideToNo: {
enableHandsFreeXToCancel = NO;
break;
}
case SCCameraTweaksStrategyFollowABTest: {
enableHandsFreeXToCancel = SCExperimentWithHandsFreeXToCancel();
break;
}
default: {
enableHandsFreeXToCancel = NO;
break;
}
}
});
return enableHandsFreeXToCancel;
}
BOOL SCCameraTweaksEnableShortPreviewTransitionAnimationDuration(void)
{
static BOOL enableShortPreviewTransitionAnimationDuration;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
switch (SCCameraTweaksPreviewTransitionAnimationDurationStrategy()) {
case SCCameraTweaksStrategyOverrideToYes: {
enableShortPreviewTransitionAnimationDuration = YES;
break;
}
case SCCameraTweaksStrategyOverrideToNo: {
enableShortPreviewTransitionAnimationDuration = NO;
break;
}
case SCCameraTweaksStrategyFollowABTest: {
enableShortPreviewTransitionAnimationDuration = SCExperimentWithShortPreviewTransitionAnimationDuration();
break;
}
default: {
enableShortPreviewTransitionAnimationDuration = YES;
break;
}
}
});
return enableShortPreviewTransitionAnimationDuration;
}
BOOL SCCameraTweaksEnablePreviewPresenterFastPreview(void)
{
static BOOL enablePreviewPresenterFastPreview;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
switch (SCCameraTweaksPreviewPresenterFastPreviewStrategy()) {
case SCCameraTweaksStrategyOverrideToYes: {
enablePreviewPresenterFastPreview = YES;
break;
}
case SCCameraTweaksStrategyOverrideToNo: {
enablePreviewPresenterFastPreview = NO;
break;
}
case SCCameraTweaksStrategyFollowABTest: {
enablePreviewPresenterFastPreview = SCExperimentWithPreviewPresenterFastPreview();
break;
}
default: {
enablePreviewPresenterFastPreview = NO;
break;
}
}
});
return enablePreviewPresenterFastPreview;
}
BOOL SCCameraTweaksEnableCaptureSharePerformer(void)
{
static BOOL enableCaptureSharePerformer;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
switch (SCCameraTweaksEnableCaptureSharePerformerStrategy()) {
case SCCameraTweaksStrategyOverrideToYes: {
enableCaptureSharePerformer = YES;
break;
}
case SCCameraTweaksStrategyOverrideToNo: {
enableCaptureSharePerformer = NO;
break;
}
case SCCameraTweaksStrategyFollowABTest: {
enableCaptureSharePerformer = SCExperimentWithCaptureSharePerformer();
break;
}
default: {
enableCaptureSharePerformer = NO;
break;
}
}
});
return enableCaptureSharePerformer;
}
static inline SCCameraTweaksStrategyType SCCameraTweaksSessionLightWeightFixStrategy(void)
{
NSNumber *strategy = SCTweakValueWithHalt(@"Camera", @"Core Camera", @"Light-weight Session Fix",
(id) @(SCCameraTweaksStrategyFollowABTest), (@{
@(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing",
@(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES",
@(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO"
}));
return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue];
}
BOOL SCCameraTweaksSessionLightWeightFixEnabled(void)
{
static BOOL enabled;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
switch (SCCameraTweaksSessionLightWeightFixStrategy()) {
case SCCameraTweaksStrategyOverrideToYes:
enabled = YES;
break;
case SCCameraTweaksStrategyOverrideToNo:
enabled = NO;
break;
case SCCameraTweaksStrategyFollowABTest:
enabled = SCExperimentWithSessionLightWeightFix();
break;
default:
enabled = NO;
break;
}
});
return enabled;
}

47
UI/AVCameraViewEnums.h

@ -0,0 +1,47 @@
//
// AVCameraViewEnums.h
// SCCamera
//
// Copyright © 2016 Snapchat, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
The context specifies the way in which the camera is presented to the user.
The controller can be configured a variety of ways depending on the context.
*/
typedef NS_ENUM(NSUInteger, AVCameraViewControllerContext) {
AVCameraViewControllerContextMainVC = 1,
AVCameraViewControllerContextReply,
AVCameraViewControllerContextDefault = AVCameraViewControllerContextReply,
AVCameraViewControllerContextSnapAds,
AVCameraViewControllerContextAddToStory,
};
typedef NS_ENUM(NSInteger, AVCameraViewType) {
AVCameraViewNoReply = 0,
AVCameraViewReplyLeft,
AVCameraViewReplyRight,
AVCameraViewChat,
AVCameraViewReplyHydra,
AVCameraViewSnapAds,
AVCameraViewGalleryMadeWithLenses,
AVCameraViewSnapConnectSnapKit,
AVCameraViewSnappable
};
typedef NS_ENUM(NSUInteger, AVCameraViewControllerRecordingState) {
AVCameraViewControllerRecordingStateDefault, // No capture activity
AVCameraViewControllerRecordingStatePrepareRecording, // Preparing for recording with delay
AVCameraViewControllerRecordingStateInitiatedRecording, // Actively recording
AVCameraViewControllerRecordingStateTakingPicture, // Taking a still image
AVCameraViewControllerRecordingStatePictureTaken, // Picture is taken
AVCameraViewControllerRecordingStatePreview, // Preparing to present preview
};
typedef NS_ENUM(NSUInteger, SCCameraRecordingMethod) {
SCCameraRecordingMethodCameraButton,
SCCameraRecordingMethodVolumeButton,
SCCameraRecordingMethodLensInitiated
};

32
UI/Lenses/LensButtonZ/SCFeatureLensButtonZ.h

@ -0,0 +1,32 @@
//
// SCFeatureLensButtonZ.h
// SCCamera
//
// Created by Anton Udovychenko on 4/24/18.
//
#import "AVCameraViewEnums.h"
#import "SCFeature.h"
#import <Foundation/Foundation.h>
@protocol SCFeatureLensButtonZ;
@class SCGrowingButton, SCLens;
NS_ASSUME_NONNULL_BEGIN
@protocol SCFeatureLensButtonZDelegate <NSObject>
- (void)featureLensZButton:(id<SCFeatureLensButtonZ>)featureLensZButton
didPressLensButton:(SCGrowingButton *)lensButton;
- (nullable NSArray<SCLens *> *)allLenses;
@end
@protocol SCFeatureLensButtonZ <SCFeature>
@property (nonatomic, weak) id<SCFeatureLensButtonZDelegate> delegate;
- (void)setLensButtonActive:(BOOL)active;
@end
NS_ASSUME_NONNULL_END

33
UI/Lenses/LensSideButton/SCFeatureLensSideButton.h

@ -0,0 +1,33 @@
//
// SCFeatureLensSideButton.h
// SCCamera
//
// Created by Anton Udovychenko on 4/12/18.
//
#import "AVCameraViewEnums.h"
#import "SCFeature.h"
#import <Foundation/Foundation.h>
@protocol SCFeatureLensSideButton;
@class SCGrowingButton, SCLens;
NS_ASSUME_NONNULL_BEGIN
@protocol SCFeatureLensSideButtonDelegate <NSObject>
- (void)featureLensSideButton:(id<SCFeatureLensSideButton>)featureLensSideButton
didPressLensButton:(SCGrowingButton *)lensButton;
- (nullable SCLens *)firstApplicableLens;
@end
@protocol SCFeatureLensSideButton <SCFeature>
@property (nonatomic, weak) id<SCFeatureLensSideButtonDelegate> delegate;
- (void)updateLensButtonVisibility:(CGFloat)visibilityPercentage;
- (void)showLensButtonIfNeeded;
@end
NS_ASSUME_NONNULL_END

24
UI/SCLongPressGestureRecognizer.h

@ -0,0 +1,24 @@
//
// SCLongPressGestureRecognizer.h
// SCCamera
//
// Created by Pavlo Antonenko on 4/28/15.
// Copyright (c) 2015 Snapchat, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
// gesture recognizer cancels, if user moved finger more then defined value, even if long press started, unlike
// UILongPressGestureRecognizer. But if user haven't moved finger for defined time, unlimited movement is allowed.
@interface SCLongPressGestureRecognizer : UILongPressGestureRecognizer
@property (nonatomic, assign) CGFloat allowableMovementAfterBegan;
@property (nonatomic, assign) CGFloat timeBeforeUnlimitedMovementAllowed;
@property (nonatomic, assign, readonly) CGFloat forceOfAllTouches;
@property (nonatomic, assign, readonly) CGFloat maximumPossibleForceOfAllTouches;
@property (nonatomic, strong) NSDictionary *userInfo;
@property (nonatomic, assign) BOOL failedByMovement;
- (BOOL)isUnlimitedMovementAllowed;
@end

88
UI/SCLongPressGestureRecognizer.m

@ -0,0 +1,88 @@
//
// SCLongPressGestureRecognizer.m
// SCCamera
//
// Created by Pavlo Antonenko on 4/28/15.
// Copyright (c) 2015 Snapchat, Inc. All rights reserved.
//
#import "SCLongPressGestureRecognizer.h"
#import <SCFoundation/SCLog.h>
#import <UIKit/UIGestureRecognizerSubclass.h>
@implementation SCLongPressGestureRecognizer {
CGPoint _initialPoint;
CGFloat _initialTime;
}
- (instancetype)initWithTarget:(id)target action:(SEL)action
{
self = [super initWithTarget:target action:action];
if (self) {
_allowableMovementAfterBegan = FLT_MAX;
_timeBeforeUnlimitedMovementAllowed = 0.0;
}
return self;
}
- (void)reset
{
[super reset];
_initialPoint = CGPointZero;
_initialTime = 0;
_forceOfAllTouches = 1.0;
_maximumPossibleForceOfAllTouches = 1.0;
self.failedByMovement = NO;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
_initialPoint = [self locationInView:self.view];
_initialTime = CACurrentMediaTime();
_forceOfAllTouches = 1.0;
for (UITouch *touch in touches) {
_maximumPossibleForceOfAllTouches = MAX(touch.maximumPossibleForce, _maximumPossibleForceOfAllTouches);
_forceOfAllTouches = MAX(touch.force, _forceOfAllTouches);
}
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
_forceOfAllTouches = 1.0;
for (UITouch *touch in touches) {
_maximumPossibleForceOfAllTouches = MAX(touch.maximumPossibleForce, _maximumPossibleForceOfAllTouches);
_forceOfAllTouches = MAX(touch.force, _forceOfAllTouches);
}
if (!CGPointEqualToPoint(_initialPoint, CGPointZero)) {
CGPoint currentPoint = [self locationInView:self.view];
CGFloat distance = hypot(_initialPoint.x - currentPoint.x, _initialPoint.y - currentPoint.y);
CGFloat timeDifference = CACurrentMediaTime() - _initialTime;
if (distance > self.allowableMovementAfterBegan && timeDifference < self.timeBeforeUnlimitedMovementAllowed) {
SCLogGeneralInfo(@"Long press moved %.2f > %.2f after %.3f < %.3f seconds, and is cancelled", distance,
self.allowableMovementAfterBegan, timeDifference, self.timeBeforeUnlimitedMovementAllowed);
self.state = UIGestureRecognizerStateFailed;
self.failedByMovement = YES;
}
}
}
- (void)setEnabled:(BOOL)enabled
{
SCLogGeneralInfo(@"Setting enabled: %d for %@", enabled, self);
[super setEnabled:enabled];
}
- (BOOL)isUnlimitedMovementAllowed
{
return CACurrentMediaTime() - _initialTime > self.timeBeforeUnlimitedMovementAllowed;
}
@end

31
VolumeButton/SCCameraVolumeButtonHandler.h

@ -0,0 +1,31 @@
//
// SCCameraVolumeButtonHandler.h
// Snapchat
//
// Created by Xiaomu Wu on 2/27/15.
// Copyright (c) 2015 Snapchat, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class SCCameraVolumeButtonHandler;
@protocol SCCameraVolumeButtonHandlerDelegate <NSObject>
- (void)volumeButtonHandlerDidBeginPressingVolumeButton:(SCCameraVolumeButtonHandler *)handler;
- (void)volumeButtonHandlerDidEndPressingVolumeButton:(SCCameraVolumeButtonHandler *)handler;
@end
@interface SCCameraVolumeButtonHandler : NSObject
@property (nonatomic, weak) id<SCCameraVolumeButtonHandlerDelegate> delegate;
- (void)startHandlingVolumeButtonEvents;
- (void)stopHandlingVolumeButtonEvents;
- (void)stopHandlingVolumeButtonEventsWhenPressingEnds;
- (BOOL)isHandlingVolumeButtonEvents;
- (BOOL)isPressingVolumeButton;
@end

190
VolumeButton/SCCameraVolumeButtonHandler.m

@ -0,0 +1,190 @@
//
// SCCameraVolumeButtonHandler.m
// Snapchat
//
// Created by Xiaomu Wu on 2/27/15.
// Copyright (c) 2015 Snapchat, Inc. All rights reserved.
//
#import "SCCameraVolumeButtonHandler.h"
#import <SCFoundation/SCLog.h>
#import <SCFoundation/UIApplication+SCSecretFeature2.h>
@implementation SCCameraVolumeButtonHandler {
NSString *_secretFeatureToken;
BOOL _pressingButton1; // volume down button
BOOL _pressingButton2; // volume up button
BOOL _stopsHandlingWhenPressingEnds;
}
#pragma mark - NSObject
- (instancetype)init
{
self = [super init];
if (self) {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
UIApplication *application = [UIApplication sharedApplication];
[notificationCenter addObserver:self
selector:@selector(_handleButton1Down:)
name:[application sc_eventNotificationName1]
object:nil];
[notificationCenter addObserver:self
selector:@selector(_handleButton1Up:)
name:[application sc_eventNotificationName2]
object:nil];
[notificationCenter addObserver:self
selector:@selector(_handleButton2Down:)
name:[application sc_eventNotificationName3]
object:nil];
[notificationCenter addObserver:self
selector:@selector(_handleButton2Up:)
name:[application sc_eventNotificationName4]
object:nil];
}
return self;
}
- (void)dealloc
{
if (_secretFeatureToken) {
[[UIApplication sharedApplication] sc_disableSecretFeature2:_secretFeatureToken];
}
}
#pragma mark - Public
- (void)startHandlingVolumeButtonEvents
{
_stopsHandlingWhenPressingEnds = NO;
[self _resetPressingButtons];
if ([self isHandlingVolumeButtonEvents]) {
return;
}
SCLogGeneralInfo(@"[Volume Buttons] Start handling volume button events");
_secretFeatureToken = [[[UIApplication sharedApplication] sc_enableSecretFeature2] copy];
}
- (void)stopHandlingVolumeButtonEvents
{
if (![self isHandlingVolumeButtonEvents]) {
return;
}
SCLogGeneralInfo(@"[Volume Buttons] Stop handling volume button events");
[[UIApplication sharedApplication] sc_disableSecretFeature2:_secretFeatureToken];
_secretFeatureToken = nil;
_stopsHandlingWhenPressingEnds = NO;
}
- (void)stopHandlingVolumeButtonEventsWhenPressingEnds
{
if (![self isHandlingVolumeButtonEvents]) {
return;
}
if (![self isPressingVolumeButton]) {
return;
}
SCLogGeneralInfo(@"[Volume Buttons] Stop handling volume button events when pressing ends");
_stopsHandlingWhenPressingEnds = YES;
}
- (BOOL)isHandlingVolumeButtonEvents
{
return (_secretFeatureToken != nil);
}
- (BOOL)isPressingVolumeButton
{
return _pressingButton1 || _pressingButton2;
}
- (void)_resetPressingButtons
{
_pressingButton1 = NO;
_pressingButton2 = NO;
}
#pragma mark - Private
- (void)_handleButton1Down:(NSNotification *)notification
{
if (![self isHandlingVolumeButtonEvents]) {
SCLogGeneralInfo(@"[Volume Buttons] Volume button 1 down, not handled");
return;
}
if (_pressingButton1) {
SCLogGeneralInfo(@"[Volume Buttons] Volume button 1 down, already down");
return;
}
SCLogGeneralInfo(@"[Volume Buttons] Volume button 1 down");
[self _changePressingButton:^{
_pressingButton1 = YES;
}];
}
- (void)_handleButton1Up:(NSNotification *)notification
{
if (![self isHandlingVolumeButtonEvents]) {
SCLogGeneralInfo(@"[Volume Buttons] Volume button 1 up, not handled");
return;
}
if (!_pressingButton1) {
SCLogGeneralInfo(@"[Volume Buttons] Volume button 1 up, already up");
return;
}
SCLogGeneralInfo(@"[Volume Buttons] Volume button 1 up");
[self _changePressingButton:^{
_pressingButton1 = NO;
}];
}
- (void)_handleButton2Down:(NSNotification *)notification
{
if (![self isHandlingVolumeButtonEvents]) {
SCLogGeneralInfo(@"[Volume Buttons] Volume button 2 down, not handled");
return;
}
if (_pressingButton2) {
SCLogGeneralInfo(@"[Volume Buttons] Volume button 2 down, already down");
return;
}
SCLogGeneralInfo(@"[Volume Buttons] Volume button 2 down");
[self _changePressingButton:^{
_pressingButton2 = YES;
}];
}
- (void)_handleButton2Up:(NSNotification *)notification
{
if (![self isHandlingVolumeButtonEvents]) {
SCLogGeneralInfo(@"[Volume Buttons] Volume button 2 up, not handled");
return;
}
if (!_pressingButton2) {
SCLogGeneralInfo(@"[Volume Buttons] Volume button 2 up, already up");
return;
}
SCLogGeneralInfo(@"[Volume Buttons] Volume button 2 up");
[self _changePressingButton:^{
_pressingButton2 = NO;
}];
}
- (void)_changePressingButton:(void (^)(void))change
{
BOOL oldPressingVolumeButton = [self isPressingVolumeButton];
change();
BOOL newPressingVolumeButton = [self isPressingVolumeButton];
if (!oldPressingVolumeButton && newPressingVolumeButton) {
[_delegate volumeButtonHandlerDidBeginPressingVolumeButton:self];
} else if (oldPressingVolumeButton && !newPressingVolumeButton) {
[_delegate volumeButtonHandlerDidEndPressingVolumeButton:self];
if (_stopsHandlingWhenPressingEnds) {
[self stopHandlingVolumeButtonEvents];
}
}
}
@end

109
Worker/SCCaptureWorker.h

@ -0,0 +1,109 @@
//
// SCCaptureWorker.h
// Snapchat
//
// Created by Lin Jia on 10/19/17.
//
//
#import "SCCaptureResource.h"
#import <SCFoundation/SCQueuePerformer.h>
#import <Foundation/Foundation.h>
/*
In general, the function of SCCapturer is to use some resources (such as SCManagedCapturerListenerAnnouncer), to do
something (such as announce an event).
SCCaptureWorker abstract away the "do something" part of SCCapturer. It has very little internal states/resources.
SCCaptureWorker is introduced to be shared between CaptureV1 and CaptureV2, to minimize duplication code.
*/
@interface SCCaptureWorker : NSObject
+ (SCCaptureResource *)generateCaptureResource;
+ (void)setupWithCaptureResource:(SCCaptureResource *)captureResource
devicePosition:(SCManagedCaptureDevicePosition)devicePosition;
+ (void)setupCapturePreviewLayerController;
+ (void)startRunningWithCaptureResource:(SCCaptureResource *)captureResource
token:(SCCapturerToken *)token
completionHandler:(dispatch_block_t)completionHandler;
+ (BOOL)stopRunningWithCaptureResource:(SCCaptureResource *)captureResource
token:(SCCapturerToken *)token
completionHandler:(sc_managed_capturer_stop_running_completion_handler_t)completionHandler;
+ (void)setupVideoPreviewLayer:(SCCaptureResource *)resource;
+ (void)makeVideoPreviewLayer:(SCCaptureResource *)resource;
+ (void)redoVideoPreviewLayer:(SCCaptureResource *)resource;
+ (void)startStreaming:(SCCaptureResource *)resource;
+ (void)setupLivenessConsistencyTimerIfForeground:(SCCaptureResource *)resource;
+ (void)destroyLivenessConsistencyTimer:(SCCaptureResource *)resource;
+ (void)softwareZoomWithDevice:(SCManagedCaptureDevice *)device resource:(SCCaptureResource *)resource;
+ (void)captureStillImageWithCaptureResource:(SCCaptureResource *)captureResource
aspectRatio:(CGFloat)aspectRatio
captureSessionID:(NSString *)captureSessionID
shouldCaptureFromVideo:(BOOL)shouldCaptureFromVideo
completionHandler:
(sc_managed_capturer_capture_still_image_completion_handler_t)completionHandler
context:(NSString *)context;
+ (void)startRecordingWithCaptureResource:(SCCaptureResource *)captureResource
outputSettings:(SCManagedVideoCapturerOutputSettings *)outputSettings
audioConfiguration:(SCAudioConfiguration *)configuration
maxDuration:(NSTimeInterval)maxDuration
fileURL:(NSURL *)fileURL
captureSessionID:(NSString *)captureSessionID
completionHandler:(sc_managed_capturer_start_recording_completion_handler_t)completionHandler;
+ (void)stopRecordingWithCaptureResource:(SCCaptureResource *)captureResource;
+ (void)cancelRecordingWithCaptureResource:(SCCaptureResource *)captureResource;
+ (SCVideoCaptureSessionInfo)activeSession:(SCCaptureResource *)resource;
+ (BOOL)canRunARSession:(SCCaptureResource *)resource;
+ (void)turnARSessionOn:(SCCaptureResource *)resource;
+ (void)turnARSessionOff:(SCCaptureResource *)resource;
+ (void)clearARKitData:(SCCaptureResource *)resource;
+ (void)updateLensesFieldOfViewTracking:(SCCaptureResource *)captureResource;
+ (CMTime)firstWrittenAudioBufferDelay:(SCCaptureResource *)resource;
+ (BOOL)audioQueueStarted:(SCCaptureResource *)resource;
+ (BOOL)isLensApplied:(SCCaptureResource *)resource;
+ (BOOL)isVideoMirrored:(SCCaptureResource *)resource;
+ (BOOL)shouldCaptureImageFromVideoWithResource:(SCCaptureResource *)resource;
+ (void)setPortraitModePointOfInterestAsynchronously:(CGPoint)pointOfInterest
completionHandler:(dispatch_block_t)completionHandler
resource:(SCCaptureResource *)resource;
+ (void)prepareForRecordingWithAudioConfiguration:(SCAudioConfiguration *)configuration
resource:(SCCaptureResource *)resource;
+ (void)stopScanWithCompletionHandler:(dispatch_block_t)completionHandler resource:(SCCaptureResource *)resource;
+ (void)startScanWithScanConfiguration:(SCScanConfiguration *)configuration resource:(SCCaptureResource *)resource;
@end

1095
Worker/SCCaptureWorker.m
File diff suppressed because it is too large
View File

Loading…
Cancel
Save