Remove ZXing.

This commit is contained in:
Matthew Chen 2021-07-01 23:05:35 -03:00
parent 1c93a4097e
commit 730ed5d281
8 changed files with 84 additions and 262 deletions

View File

@ -71,7 +71,6 @@
340FC8AB204DAC8D007AEB0F /* DomainFrontingCountryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC87D204DAC8C007AEB0F /* DomainFrontingCountryViewController.m */; };
340FC8AF204DAC8D007AEB0F /* OWSLinkDeviceViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC885204DAC8C007AEB0F /* OWSLinkDeviceViewController.m */; };
340FC8B1204DAC8D007AEB0F /* BlockListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC887204DAC8C007AEB0F /* BlockListViewController.m */; };
340FC8B6204DAC8D007AEB0F /* OWSQRCodeScanningViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC896204DAC8C007AEB0F /* OWSQRCodeScanningViewController.m */; };
340FC8BA204DAC8D007AEB0F /* FingerprintViewScanController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC89F204DAC8D007AEB0F /* FingerprintViewScanController.m */; };
340FC8BC204DAC8D007AEB0F /* FingerprintViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC8A2204DAC8D007AEB0F /* FingerprintViewController.m */; };
34123C5E239AA3E900782788 /* TooltipView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34123C5D239AA3E900782788 /* TooltipView.swift */; };
@ -1090,11 +1089,9 @@
340FC87D204DAC8C007AEB0F /* DomainFrontingCountryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DomainFrontingCountryViewController.m; sourceTree = "<group>"; };
340FC885204DAC8C007AEB0F /* OWSLinkDeviceViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSLinkDeviceViewController.m; sourceTree = "<group>"; };
340FC887204DAC8C007AEB0F /* BlockListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BlockListViewController.m; sourceTree = "<group>"; };
340FC888204DAC8C007AEB0F /* OWSQRCodeScanningViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSQRCodeScanningViewController.h; sourceTree = "<group>"; };
340FC889204DAC8C007AEB0F /* DomainFrontingCountryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DomainFrontingCountryViewController.h; sourceTree = "<group>"; };
340FC890204DAC8C007AEB0F /* BlockListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlockListViewController.h; sourceTree = "<group>"; };
340FC891204DAC8C007AEB0F /* OWSLinkDeviceViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSLinkDeviceViewController.h; sourceTree = "<group>"; };
340FC896204DAC8C007AEB0F /* OWSQRCodeScanningViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSQRCodeScanningViewController.m; sourceTree = "<group>"; };
340FC89D204DAC8D007AEB0F /* FingerprintViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FingerprintViewController.h; sourceTree = "<group>"; };
340FC89F204DAC8D007AEB0F /* FingerprintViewScanController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FingerprintViewScanController.m; sourceTree = "<group>"; };
340FC8A2204DAC8D007AEB0F /* FingerprintViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FingerprintViewController.m; sourceTree = "<group>"; };
@ -3690,8 +3687,6 @@
3437F6392512835200AC1767 /* LinkedDevicesTableViewController.swift */,
340FC891204DAC8C007AEB0F /* OWSLinkDeviceViewController.h */,
340FC885204DAC8C007AEB0F /* OWSLinkDeviceViewController.m */,
340FC888204DAC8C007AEB0F /* OWSQRCodeScanningViewController.h */,
340FC896204DAC8C007AEB0F /* OWSQRCodeScanningViewController.m */,
345779402682464700732869 /* ScanQRCodeViewController.swift */,
);
path = "Linked Devices";
@ -5807,7 +5802,6 @@
887889A52476E999001B5FCF /* OWSPinConfirmationViewController.swift in Sources */,
347030C625F66C24006C3BF5 /* PaymentsDeactivateViewController.swift in Sources */,
346594802434D49F00E5C510 /* NewGroupState.swift in Sources */,
340FC8B6204DAC8D007AEB0F /* OWSQRCodeScanningViewController.m in Sources */,
4CB5F26920F7D060004D1B42 /* MessageActions.swift in Sources */,
346EFC40260276E400F493C7 /* PaymentsRestoreWalletPasteboardViewController.swift in Sources */,
8841584C252F9F1C0078903D /* SignalCall.swift in Sources */,

View File

@ -2,7 +2,6 @@
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
//
#import "OWSQRCodeScanningViewController.h"
#import <SignalMessaging/OWSViewController.h>
NS_ASSUME_NONNULL_BEGIN
@ -21,8 +20,6 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, weak) id<OWSLinkDeviceViewControllerDelegate> delegate;
- (void)controller:(nullable OWSQRCodeScanningViewController *)controller didDetectQRCodeWithString:(NSString *)string;
- (void)provisionWithConfirmationWithParser:(OWSDeviceProvisioningURLParser *)parser;
@end

View File

@ -15,11 +15,11 @@
NS_ASSUME_NONNULL_BEGIN
@interface OWSLinkDeviceViewController () <OWSQRScannerDelegate>
@interface OWSLinkDeviceViewController () <QRCodeScanDelegate>
@property (nonatomic) UIView *qrScanningView;
@property (nonatomic) UILabel *scanningInstructionsLabel;
@property (nonatomic) OWSQRCodeScanningViewController *qrScanningController;
@property (nonatomic) QRCodeScanViewController *qrCodeScanViewController;
@property (nonatomic, readonly) OWSReceiptManager *receiptManager;
@end
@ -43,17 +43,18 @@ NS_ASSUME_NONNULL_BEGIN
self.scanningInstructionsLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.scanningInstructionsLabel.textAlignment = NSTextAlignmentCenter;
self.qrScanningController = [OWSQRCodeScanningViewController new];
self.qrScanningController.scanDelegate = self;
[self.view addSubview:self.qrScanningController.view];
[self.qrScanningController.view autoPinEdgeToSuperviewEdge:ALEdgeLeading];
[self.qrScanningController.view autoPinEdgeToSuperviewEdge:ALEdgeTrailing];
[self.qrScanningController.view autoPinToTopLayoutGuideOfViewController:self withInset:0.f];
[self.qrScanningController.view autoPinToSquareAspectRatio];
self.qrCodeScanViewController = [QRCodeScanViewController new];
self.qrCodeScanViewController.delegate = self;
[self.view addSubview:self.qrCodeScanViewController.view];
[self.qrCodeScanViewController.view autoPinEdgeToSuperviewEdge:ALEdgeLeading];
[self.qrCodeScanViewController.view autoPinEdgeToSuperviewEdge:ALEdgeTrailing];
[self.qrCodeScanViewController.view autoPinToTopLayoutGuideOfViewController:self withInset:0.f];
[self.qrCodeScanViewController.view autoPinToSquareAspectRatio];
[self addChildViewController:self.qrCodeScanViewController];
UIView *bottomView = [UIView new];
[self.view addSubview:bottomView];
[bottomView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.qrScanningController.view];
[bottomView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.qrCodeScanViewController.view];
[bottomView autoPinEdgeToSuperviewEdge:ALEdgeLeading];
[bottomView autoPinEdgeToSuperviewEdge:ALEdgeTrailing];
[bottomView autoPinEdgeToSuperviewEdge:ALEdgeBottom];
@ -91,10 +92,6 @@ NS_ASSUME_NONNULL_BEGIN
if (!UIDevice.currentDevice.isIPad) {
[UIDevice.currentDevice ows_setOrientation:UIDeviceOrientationPortrait];
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.qrScanningController startCapture];
});
}
- (void)traitCollectionDidChange:(nullable UITraitCollection *)previousTraitCollection
@ -105,13 +102,29 @@ NS_ASSUME_NONNULL_BEGIN
self.scanningInstructionsLabel.textColor = Theme.primaryTextColor;
}
#pragma mark - OWSQRScannerDelegate
#pragma mark - QRCodeScanDelegate
- (void)controller:(nullable OWSQRCodeScanningViewController *)controller didDetectQRCodeWithString:(NSString *)string
- (void)qrCodeScanViewDismiss:(QRCodeScanViewController *)qrCodeScanViewController
{
OWSDeviceProvisioningURLParser *parser = [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:string];
OWSAssertIsOnMainThread();
[self popToLinkedDeviceList];
}
- (QRCodeScanOutcome)qrCodeScanViewScanned:(QRCodeScanViewController *)qrCodeScanViewController
qrCodeData:(nullable NSData *)qrCodeData
qrCodeString:(nullable NSString *)qrCodeString
{
OWSAssertIsOnMainThread();
if (qrCodeString == nil) {
// Only accept QR codes with a valid string payload.
return QRCodeScanOutcomeContinueScanning;
}
OWSDeviceProvisioningURLParser *parser = [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:qrCodeString];
if (!parser.isValid) {
OWSLogError(@"Unable to parse provisioning params from QRCode: %@", string);
OWSLogError(@"Unable to parse provisioning params from QRCode: %@", qrCodeString);
NSString *title = NSLocalizedString(@"LINK_DEVICE_INVALID_CODE_TITLE", @"report an invalid linking code");
NSString *body = NSLocalizedString(@"LINK_DEVICE_INVALID_CODE_BODY", @"report an invalid linking code");
@ -132,7 +145,7 @@ NS_ASSUME_NONNULL_BEGIN
initWithTitle:NSLocalizedString(@"LINK_DEVICE_RESTART", @"attempt another linking")
style:ActionSheetActionStyleDefault
handler:^(ActionSheetAction *action) {
[self.qrScanningController startCapture];
[self.qrCodeScanViewController tryToStartScanning];
}];
[actionSheet addAction:proceedAction];
@ -140,6 +153,8 @@ NS_ASSUME_NONNULL_BEGIN
} else {
[self provisionWithConfirmationWithParser:parser];
}
return QRCodeScanOutcomeStopScanning;
}
- (void)provisionWithConfirmationWithParser:(OWSDeviceProvisioningURLParser *)parser
@ -267,8 +282,10 @@ NS_ASSUME_NONNULL_BEGIN
actionWithTitle:CommonStrings.okayButton
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
[self controller:nil
didDetectQRCodeWithString:[alertController textFields].firstObject.text];
NSString *qrCodeString = [alertController textFields].firstObject.text;
[self qrCodeScanViewScanned:self.qrCodeScanViewController
qrCodeData:nil
qrCodeString:qrCodeString];
}]];
[alertController addAction:[UIAlertAction actionWithTitle:CommonStrings.cancelButton
style:UIAlertActionStyleCancel

View File

@ -1,34 +0,0 @@
//
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
//
#import <AVFoundation/AVFoundation.h>
#import <SignalMessaging/OWSViewController.h>
#import <UIKit/UIKit.h>
#import <ZXingObjC/ZXingObjC.h>
NS_ASSUME_NONNULL_BEGIN
@class OWSQRCodeScanningViewController;
@protocol OWSQRScannerDelegate
@optional
- (void)controller:(OWSQRCodeScanningViewController *)controller didDetectQRCodeWithString:(NSString *)string;
- (void)controller:(OWSQRCodeScanningViewController *)controller didDetectQRCodeWithData:(NSData *)data;
@end
#pragma mark -
@interface OWSQRCodeScanningViewController
: OWSViewController <AVCaptureMetadataOutputObjectsDelegate, ZXCaptureDelegate>
@property (nonatomic, weak) UIViewController<OWSQRScannerDelegate> *scanDelegate;
- (void)startCapture;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,146 +0,0 @@
//
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
//
#import "OWSQRCodeScanningViewController.h"
#import "OWSBezierPathView.h"
#import "UIView+OWS.h"
NS_ASSUME_NONNULL_BEGIN
@interface OWSQRCodeScanningViewController ()
@property (atomic) ZXCapture *capture;
@property (nonatomic) BOOL captureEnabled;
@property (nonatomic) UIView *maskingView;
@end
#pragma mark -
@implementation OWSQRCodeScanningViewController
- (void)dealloc
{
[self.capture.layer removeFromSuperlayer];
}
- (instancetype)init
{
self = [super init];
if (!self) {
return self;
}
_captureEnabled = NO;
return self;
}
- (void)loadView
{
[super loadView];
OWSBezierPathView *maskingView = [OWSBezierPathView new];
self.maskingView = maskingView;
[maskingView setConfigureShapeLayerBlock:^(CAShapeLayer *layer, CGRect bounds) {
// Add a circular mask
UIBezierPath *path = [UIBezierPath bezierPathWithRect:bounds];
CGFloat margin = ScaleFromIPhone5To7Plus(8.f, 16.f);
CGFloat radius = MIN(bounds.size.width, bounds.size.height) * 0.5f - margin;
// Center the circle's bounding rectangle
CGRect circleRect = CGRectMake(
bounds.size.width * 0.5f - radius, bounds.size.height * 0.5f - radius, radius * 2.f, radius * 2.f);
UIBezierPath *circlePath = [UIBezierPath bezierPathWithRoundedRect:circleRect cornerRadius:radius];
[path appendPath:circlePath];
[path setUsesEvenOddFillRule:YES];
layer.path = path.CGPath;
layer.fillRule = kCAFillRuleEvenOdd;
layer.fillColor = [UIColor grayColor].CGColor;
layer.opacity = 0.5f;
}];
[self.view addSubview:maskingView];
[maskingView autoPinEdgesToSuperviewEdges];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (self.captureEnabled) {
[self startCapture];
}
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self stopCapture];
}
- (void)viewWillLayoutSubviews
{
self.capture.layer.frame = self.view.bounds;
}
- (void)startCapture
{
self.captureEnabled = YES;
if (!self.capture) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
self.capture = [[ZXCapture alloc] init];
self.capture.camera = self.capture.back;
self.capture.focusMode = AVCaptureFocusModeContinuousAutoFocus;
self.capture.delegate = self;
dispatch_async(dispatch_get_main_queue(), ^{
self.capture.layer.frame = self.view.bounds;
[self.view.layer addSublayer:self.capture.layer];
[self.view bringSubviewToFront:self.maskingView];
[self.capture start];
});
});
} else {
[self.capture start];
}
}
- (void)stopCapture
{
self.captureEnabled = NO;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.capture stop];
});
}
- (void)captureResult:(ZXCapture *)capture result:(ZXResult *)result
{
if (!self.captureEnabled) {
return;
}
[self stopCapture];
// Vibrate
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
if (self.scanDelegate) {
if ([self.scanDelegate respondsToSelector:@selector(controller:didDetectQRCodeWithData:)]) {
OWSLogInfo(@"Scanned Data Code.");
ZXByteArray *byteArray = result.resultMetadata[@(kResultMetadataTypeByteSegments)][0];
NSData *decodedData = [NSData dataWithBytes:byteArray.array length:byteArray.length];
[self.scanDelegate controller:self didDetectQRCodeWithData:decodedData];
}
if ([self.scanDelegate respondsToSelector:@selector(controller:didDetectQRCodeWithString:)]) {
OWSLogInfo(@"Scanned String Code.");
[self.scanDelegate controller:self didDetectQRCodeWithString:result.text];
}
}
}
@end
NS_ASSUME_NONNULL_END

View File

@ -7,12 +7,19 @@ import AVFoundation
import PromiseKit
import Vision
@objc
public enum QRCodeScanOutcome: UInt {
case stopScanning
case continueScanning
}
// MARK: -
@objc
protocol QRCodeScanDelegate: AnyObject {
// Should return true IFF the qrCode was accepted.
func qrCodeScanViewScanned(_ qrCodeScanViewController: QRCodeScanViewController,
qrCodeData value: Data?,
qrCodeString value: String?) -> Bool
qrCodeData: Data?,
qrCodeString: String?) -> QRCodeScanOutcome
func qrCodeScanViewDismiss(_ qrCodeScanViewController: QRCodeScanViewController)
}
@ -297,14 +304,17 @@ class QRCodeScanViewController: OWSViewController {
return
}
let accepted = delegate.qrCodeScanViewScanned(self,
let outcome = delegate.qrCodeScanViewScanned(self,
qrCodeData: qrCode.qrCodeData,
qrCodeString: qrCode.qrCodeString)
if accepted {
switch outcome {
case .stopScanning:
self.stopScanning()
// Vibrate
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
case .continueScanning:
break
}
}
}

View File

@ -14,7 +14,7 @@ public class PaymentsQRScanViewController: OWSViewController {
private weak var delegate: PaymentsQRScanDelegate?
private let qrScanningController = OWSQRCodeScanningViewController()
private let qrCodeScanViewController = QRCodeScanViewController()
public required init(delegate: PaymentsQRScanDelegate) {
self.delegate = delegate
@ -44,29 +44,14 @@ public class PaymentsQRScanViewController: OWSViewController {
public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.ows_askForCameraPermissions { [weak self] granted in
guard let self = self else {
return
}
if granted {
// Camera stops capturing when "sharing" while in capture mode.
// Also, it's less obvious whats being "shared" at this point,
// so just disable sharing when in capture mode.
Logger.info("Showing Scanner")
self.qrScanningController.startCapture()
} else {
self.didTapCancel()
}
}
}
private func createViews() {
view.backgroundColor = .ows_black
qrScanningController.scanDelegate = self
let qrView = qrScanningController.view!
qrCodeScanViewController.delegate = self
addChild(qrCodeScanViewController)
let qrView = qrCodeScanViewController.view!
view.addSubview(qrView)
qrView.autoPinWidthToSuperview()
qrView.autoPin(toTopLayoutGuideOf: self, withInset: 0)
@ -102,34 +87,34 @@ public class PaymentsQRScanViewController: OWSViewController {
// MARK: -
extension PaymentsQRScanViewController: OWSQRScannerDelegate {
public func controller(_ controller: OWSQRCodeScanningViewController, didDetectQRCodeWith data: Data) {
if let dataString = String(data: data, encoding: .utf8) {
if nil != PaymentsImpl.parse(publicAddressBase58: dataString) {
delegate?.didScanPaymentAddressQRCode(publicAddressBase58: dataString)
extension PaymentsQRScanViewController: QRCodeScanDelegate {
func qrCodeScanViewDismiss(_ qrCodeScanViewController: QRCodeScanViewController) {
AssertIsOnMainThread()
navigationController?.popViewController(animated: true)
}
func qrCodeScanViewScanned(_ qrCodeScanViewController: QRCodeScanViewController,
qrCodeData: Data?,
qrCodeString: String?) -> QRCodeScanOutcome {
AssertIsOnMainThread()
if let qrCodeString = qrCodeString {
if nil != PaymentsImpl.parse(publicAddressBase58: qrCodeString) {
delegate?.didScanPaymentAddressQRCode(publicAddressBase58: qrCodeString)
navigationController?.popViewController(animated: true)
return
} else if let publicAddressUrl = URL(string: dataString),
return .stopScanning
} else if let publicAddressUrl = URL(string: qrCodeString),
let publicAddress = PaymentsImpl.parseAsPublicAddress(url: publicAddressUrl) {
let publicAddressBase58 = PaymentsImpl.formatAsBase58(publicAddress: publicAddress)
delegate?.didScanPaymentAddressQRCode(publicAddressBase58: publicAddressBase58)
navigationController?.popViewController(animated: true)
return
return .stopScanning
}
}
OWSActionSheets.showErrorAlert(message: NSLocalizedString("SETTINGS_PAYMENTS_SCAN_QR_INVALID_PUBLIC_ADDRESS",
comment: "Error indicating that a QR code does not contain a valid MobileCoin public address."))
}
public func controller(_ controller: OWSQRCodeScanningViewController, didDetectQRCodeWith string: String) {
guard let publicAddressUrl = URL(string: string),
let publicAddress = PaymentsImpl.parseAsPublicAddress(url: publicAddressUrl) else {
OWSActionSheets.showErrorAlert(message: NSLocalizedString("SETTINGS_PAYMENTS_SCAN_QR_INVALID_PUBLIC_ADDRESS_URL",
comment: "Error indicating that a QR code does not contain a valid MobileCoin public address URL."))
return
}
let publicAddressBase58 = PaymentsImpl.formatAsBase58(publicAddress: publicAddress)
delegate?.didScanPaymentAddressQRCode(publicAddressBase58: publicAddressBase58)
navigationController?.popViewController(animated: true)
}
return .continueScanning
}
}

View File

@ -71,7 +71,6 @@ NS_ASSUME_NONNULL_BEGIN
[self.view addSubview:self.qrCodeScanViewController.view];
[self.qrCodeScanViewController.view autoPinWidthToSuperview];
[self.qrCodeScanViewController.view autoPinToTopLayoutGuideOfViewController:self withInset:0];
[self.qrCodeScanViewController.view addRedBorder];
[self addChildViewController:self.qrCodeScanViewController];
UIView *footer = [UIView new];
@ -105,21 +104,21 @@ NS_ASSUME_NONNULL_BEGIN
[self.navigationController popViewControllerAnimated:YES];
}
- (BOOL)qrCodeScanViewScanned:(QRCodeScanViewController *)qrCodeScanViewController
qrCodeData:(nullable NSData *)qrCodeData
qrCodeString:(nullable NSString *)qrCodeString
- (QRCodeScanOutcome)qrCodeScanViewScanned:(QRCodeScanViewController *)qrCodeScanViewController
qrCodeData:(nullable NSData *)qrCodeData
qrCodeString:(nullable NSString *)qrCodeString
{
OWSAssertIsOnMainThread();
if (qrCodeData == nil) {
// Only accept QR codes with a valid data (not string) payload.
return NO;
return QRCodeScanOutcomeContinueScanning;
}
[self verifyCombinedFingerprintData:qrCodeData];
// Accept the QR code even if verification failed.
return YES;
// Stop scanning even if verification failed.
return QRCodeScanOutcomeStopScanning;
}
- (void)verifyCombinedFingerprintData:(NSData *)combinedFingerprintData