Commit 723d89c1 authored by Tanisha Mandre's avatar Tanisha Mandre Committed by Commit Bot

Refactor QR scanner view controller files to subclass from Scanner View Controller

Architecture:
Superclass - scannerView
Subclasses - qrScannerView

Files just renamed and shifted to scanner directory:
- camera_controller
- qr_scanner_alerts
- qr_transitioning_delegate
- qr_scanner_presenting

Bug: 990744

Change-Id: I3fddd13f05e1a2bdd5de239c32f86979399eb925
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1741974
Commit-Queue: Tanisha Mandre <tanishamandre@google.com>
Reviewed-by: default avatarEric Noyau <noyau@chromium.org>
Reviewed-by: default avatarJavier Ernesto Flores Robles <javierrobles@chromium.org>
Cr-Commit-Position: refs/heads/master@{#688254}
parent 60a9fb66
...@@ -237,22 +237,22 @@ locale. The strings in this file are specific to iOS. ...@@ -237,22 +237,22 @@ locale. The strings in this file are specific to iOS.
<message name="IDS_IOS_PRODUCT_NAME" desc="The Chrome application name"> <message name="IDS_IOS_PRODUCT_NAME" desc="The Chrome application name">
Chromium Chromium
</message> </message>
<message name="IDS_IOS_QR_SCANNER_CAMERA_IN_USE_ALERT_DETAIL" desc="Body of a modal dialog shown when the user tries to open the QR scanner but the camera is in use by another application. [Length: 140em] [iOS only]"> <message name="IDS_IOS_SCANNER_CAMERA_IN_USE_ALERT_DETAIL" desc="Body of a modal dialog shown when the user tries to open the QR or credit card scanner but the camera is in use by another application. [Length: 140em] [iOS only]">
Chromium can't use your camera because it's in use by another application Chromium can't use your camera because it's in use by another application
</message> </message>
<message name="IDS_IOS_QR_SCANNER_CAMERA_PERMISSIONS_HELP_DETAIL" desc="Body of modal dialog shown when the user tries to open the QR scanner but the application lacks permission to use the camera. The text instructs the user how to change the permissions setting. [Length: 140em] [iOS only]"> <message name="IDS_IOS_SCANNER_CAMERA_PERMISSIONS_HELP_DETAIL" desc="Body of modal dialog shown when the user tries to open the QR or credit card scanner but the application lacks permission to use the camera. The text instructs the user how to change the permissions setting. [Length: 140em] [iOS only]">
Open Settings &gt; Privacy &gt; Camera &gt; Chromium and turn on the camera. Open Settings &gt; Privacy &gt; Camera &gt; Chromium and turn on the camera.
</message> </message>
<message name="IDS_IOS_QR_SCANNER_CAMERA_PERMISSIONS_HELP_TITLE" desc="Title of modal dialog shown when the user tries to open the QR scanner but the application lacks permission to use the camera. The body of this dialog instructs the user how to change the permissions setting. [Length: 50em] [iOS only]"> <message name="IDS_IOS_SCANNER_CAMERA_PERMISSIONS_HELP_TITLE" desc="Title of modal dialog shown when the user tries to open the QR or Credit Card scanner but the application lacks permission to use the camera. The body of this dialog instructs the user how to change the permissions setting. [Length: 50em] [iOS only]">
Start using Chromium QR scanner Start using Chromium scanner
</message> </message>
<message name="IDS_IOS_QR_SCANNER_CAMERA_PERMISSIONS_HELP_TITLE_GO_TO_SETTINGS" desc="Title of modal dialog shown when the user tries to open the QR scanner but the application lacks permission to use the camera. [Length: 40em] [iOS only]"> <message name="IDS_IOS_SCANNER_CAMERA_PERMISSIONS_HELP_TITLE_GO_TO_SETTINGS" desc="Title of modal dialog shown when the user tries to open the QR or credit card scanner but the application lacks permission to use the camera. [Length: 40em] [iOS only]">
Turn on Chromium QR scanner Turn on Chromium scanner
</message> </message>
<message name="IDS_IOS_QR_SCANNER_CAMERA_UNAVAILABLE_ALERT_DETAIL" desc="Body of a modal dialog shown when the user tries to open the QR scanner but the camera is unavailable. [Length: 140em] [iOS only]"> <message name="IDS_IOS_SCANNER_CAMERA_UNAVAILABLE_ALERT_DETAIL" desc="Body of a modal dialog shown when the user tries to open the QR or credit card scanner but the camera is unavailable. [Length: 140em] [iOS only]">
Chromium can't use your camera right now Chromium can't use your camera right now
</message> </message>
<message name="IDS_IOS_QR_SCANNER_MULTIPLE_FOREGROUND_APPS_ALERT_DETAIL" desc="Body of a modal dialog shown when the user tries to open the QR scanner in a Split View mode, when the camera is unavailable. [Length: 140em] [iOS only]"> <message name="IDS_IOS_SCANNER_MULTIPLE_FOREGROUND_APPS_ALERT_DETAIL" desc="Body of a modal dialog shown when the user tries to open the QR or credit card scanner in a Split View mode, when the camera is unavailable. [Length: 140em] [iOS only]">
Chromium can't use your camera in Split View mode Chromium can't use your camera in Split View mode
</message> </message>
<message name="IDS_IOS_SAFE_MODE_NAMED_TWEAKS_FOUND" desc="The message indicating a 3rd party tweak has been found that is known to crash Chromium. After the ':', we will list the names of the libraries. [Length: 140em]"> <message name="IDS_IOS_SAFE_MODE_NAMED_TWEAKS_FOUND" desc="The message indicating a 3rd party tweak has been found that is known to crash Chromium. After the ':', we will list the names of the libraries. [Length: 140em]">
......
...@@ -246,8 +246,8 @@ locale. The strings in this file are specific to iOS. ...@@ -246,8 +246,8 @@ locale. The strings in this file are specific to iOS.
<message name="IDS_IOS_QR_SCANNER_CAMERA_PERMISSIONS_HELP_TITLE" desc="Title of modal dialog shown when the user tries to open the QR scanner but the application lacks permission to use the camera. The body of this dialog instructs the user how to change the permissions setting. [Length: 50em] [iOS only]"> <message name="IDS_IOS_QR_SCANNER_CAMERA_PERMISSIONS_HELP_TITLE" desc="Title of modal dialog shown when the user tries to open the QR scanner but the application lacks permission to use the camera. The body of this dialog instructs the user how to change the permissions setting. [Length: 50em] [iOS only]">
Start using Google Chrome QR scanner Start using Google Chrome QR scanner
</message> </message>
<message name="IDS_IOS_QR_SCANNER_CAMERA_PERMISSIONS_HELP_TITLE_GO_TO_SETTINGS" desc="Title of modal dialog shown when the user tries to open the QR scanner but the application lacks permission to use the camera. [Length: 40em] [iOS only]"> <message name="IDS_IOS_SCANNER_CAMERA_PERMISSIONS_HELP_TITLE_GO_TO_SETTINGS" desc="Title of modal dialog shown when the user tries to open the QR or credit card scanner but the application lacks permission to use the camera. [Length: 40em] [iOS only]">
Turn on Google Chrome QR scanner Chrome Would Like to Access the Camera
</message> </message>
<message name="IDS_IOS_QR_SCANNER_CAMERA_UNAVAILABLE_ALERT_DETAIL" desc="Body of a modal dialog shown when the user tries to open the QR scanner but the camera is unavailable. [Length: 140em] [iOS only]"> <message name="IDS_IOS_QR_SCANNER_CAMERA_UNAVAILABLE_ALERT_DETAIL" desc="Body of a modal dialog shown when the user tries to open the QR scanner but the camera is unavailable. [Length: 140em] [iOS only]">
Google Chrome can't use your camera right now Google Chrome can't use your camera right now
......
...@@ -1250,13 +1250,13 @@ Handoff must also be enabled in the General section of Settings, and your device ...@@ -1250,13 +1250,13 @@ Handoff must also be enabled in the General section of Settings, and your device
<message name="IDS_IOS_QR_SCANNER_MULTIPLE_FOREGROUND_APPS_ALERT_TITLE" desc="Title of a modal dialog shown when the user tries to open the QR scanner in a Split View mode. [Length: 40em] [iOS only]" meaning="Title of a Split View error dialog in QR Scanner."> <message name="IDS_IOS_QR_SCANNER_MULTIPLE_FOREGROUND_APPS_ALERT_TITLE" desc="Title of a modal dialog shown when the user tries to open the QR scanner in a Split View mode. [Length: 40em] [iOS only]" meaning="Title of a Split View error dialog in QR Scanner.">
Split View Split View
</message> </message>
<message name="IDS_IOS_SCANNER_TORCH_BUTTON_ACCESSIBILITY_LABEL" desc="Accessibility label for the button to turn torch on and off in the scanner. The current state of the button is communicated using the accessibility value. [Length: unlimited] [iOS only]"> <message name="IDS_IOS_SCANNER_TORCH_BUTTON_ACCESSIBILITY_LABEL" desc="Accessibility label for the button to turn torch on and off in the Scanner. The current state of the button is communicated using the accessibility value. [Length: unlimited] [iOS only]" meaning="The button to turn on and off the torch. [20em] [Read by Text-to-Speech]">
Torch Torch
</message> </message>
<message name="IDS_IOS_SCANNER_TORCH_OFF_ACCESSIBILITY_VALUE" desc="Accessiblity value of the button to turn torch on in the scanner. The button communicates that the torch is current off. [Length: unlimited] [iOS only]"> <message name="IDS_IOS_SCANNER_TORCH_OFF_ACCESSIBILITY_VALUE" desc="Accessiblity value of the button to turn torch on in the Scanner. The button communicates that the torch is current off. [Length: unlimited] [iOS only]" meaning="The user will put off the torch [20em] [Read by Text-to-Speech]">
Off Off
</message> </message>
<message name="IDS_IOS_SCANNER_TORCH_ON_ACCESSIBILITY_VALUE" desc="Accessibility value of the button to turn torch off in the scanner. The button communicates that the torch is currently on. [Length: unlimited] [iOS only]"> <message name="IDS_IOS_SCANNER_TORCH_ON_ACCESSIBILITY_VALUE" desc="Accessibility value of the button to turn torch off in the Scanner. The button communicates that the torch is currently on. [Length: unlimited] [iOS only]" meaning="The user will put on the torch [20em] [Read by Text-to-Speech]">
On On
</message> </message>
<message name="IDS_IOS_QR_SCANNER_VIEWPORT_CAPTION" desc="Message displayed below the QR scanner viewport instructing the user to position the scanned QR or bar code inside the viewport. [Length: unlimited] [iOS only]"> <message name="IDS_IOS_QR_SCANNER_VIEWPORT_CAPTION" desc="Message displayed below the QR scanner viewport instructing the user to position the scanned QR or bar code inside the viewport. [Length: unlimited] [iOS only]">
...@@ -1277,6 +1277,27 @@ Handoff must also be enabled in the General section of Settings, and your device ...@@ -1277,6 +1277,27 @@ Handoff must also be enabled in the General section of Settings, and your device
<message name="IDS_IOS_READING_LIST_CANCEL_BUTTON" desc="Label of the button to stop editing the reading list entries (delete, mark as read/unread) [Length: 25em]" meaning="Stop editing. [Length: 25em]"> <message name="IDS_IOS_READING_LIST_CANCEL_BUTTON" desc="Label of the button to stop editing the reading list entries (delete, mark as read/unread) [Length: 25em]" meaning="Stop editing. [Length: 25em]">
Cancel Cancel
</message> </message>
<message name="IDS_IOS_SCANNER_ALERT_CANCEL" desc="Title for a button to cancel a Scanner error dialog. The dialog will be dismissed and no action will be taken. [Length: 20em] [iOS only]" meaning="A button to cancel a Scanner error dialog.">
Cancel
</message>
<message name="IDS_IOS_SCANNER_CAMERA_IN_USE_ALERT_TITLE" desc="Title of a modal dialog shown when the user tries to open the scanner but the camera is in use by another application. [Length: 40em] [iOS only]">
Camera is in use
</message>
<message name="IDS_IOS_SCANNER_CAMERA_PERMISSIONS_HELP_DETAIL_GO_TO_SETTINGS" desc="Body of modal dialog shown when the user tries to open the scanner but the application lacks permission to use the camera. This body tells the users they'll be redirected to the Settings app. [Length: 140em] [iOS only]">
To scan a QR code or credit card, enable the camera from settings.
</message>
<message name="IDS_IOS_SCANNER_CAMERA_PERMISSIONS_HELP_GO_TO_SETTINGS" desc="Title for a button to go to System settings app. [Length: 20em] [iOS only]">
Settings
</message>
<message name="IDS_IOS_SCANNER_CAMERA_UNAVAILABLE_ALERT_TITLE" desc="Title of a modal dialog shown when the user tries to open the scanner but the camera is unavailable. [Length: 40em] [iOS only]">
Camera is unavailable
</message>
<message name="IDS_IOS_SCANNER_SCANNED_ACCESSIBILITY_ANNOUNCEMENT" desc="The accessibility announcement read by Voice Over when the user scans a QR code, bar code, or Credit Card. [Length: unlimited] [iOS only]">
Scanned
</message>
<message name="IDS_IOS_SCANNER_MULTIPLE_FOREGROUND_APPS_ALERT_TITLE" desc="Title of a modal dialog shown when the user tries to open the scanner in a Split View mode. [Length: 40em] [iOS only]" meaning="Title of a Split View error dialog in Scanner.">
Split View
</message>
<message name="IDS_IOS_TOOLS_MENU_CELL_NEW_FEATURE_BADGE" desc="Title and accessibility label of the badge displayed on a tools menu item when it represents a new feature [Length: 20em]" meaning="A badge with this title is displayed informing the user that this feature that is new to them."> <message name="IDS_IOS_TOOLS_MENU_CELL_NEW_FEATURE_BADGE" desc="Title and accessibility label of the badge displayed on a tools menu item when it represents a new feature [Length: 20em]" meaning="A badge with this title is displayed informing the user that this feature that is new to them.">
New New
</message> </message>
......
...@@ -5,13 +5,6 @@ ...@@ -5,13 +5,6 @@
source_set("qr_scanner") { source_set("qr_scanner") {
configs += [ "//build/config/compiler:enable_arc" ] configs += [ "//build/config/compiler:enable_arc" ]
sources = [ sources = [
"camera_controller.h",
"camera_controller.mm",
"qr_scanner_alerts.h",
"qr_scanner_alerts.mm",
"qr_scanner_presenting.h",
"qr_scanner_transitioning_delegate.h",
"qr_scanner_transitioning_delegate.mm",
"qr_scanner_view.h", "qr_scanner_view.h",
"qr_scanner_view.mm", "qr_scanner_view.mm",
"qr_scanner_view_controller.h", "qr_scanner_view_controller.h",
...@@ -47,6 +40,7 @@ source_set("coordinator") { ...@@ -47,6 +40,7 @@ source_set("coordinator") {
"//base", "//base",
"//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/commands",
"//ios/chrome/browser/ui/coordinators:chrome_coordinators", "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
"//ios/chrome/browser/ui/scanner",
"//ios/chrome/browser/ui/toolbar/public", "//ios/chrome/browser/ui/toolbar/public",
] ]
} }
...@@ -70,6 +64,7 @@ source_set("eg_tests") { ...@@ -70,6 +64,7 @@ source_set("eg_tests") {
"//ios/chrome/browser/ui/icons", "//ios/chrome/browser/ui/icons",
"//ios/chrome/browser/ui/location_bar", "//ios/chrome/browser/ui/location_bar",
"//ios/chrome/browser/ui/omnibox", "//ios/chrome/browser/ui/omnibox",
"//ios/chrome/browser/ui/scanner",
"//ios/chrome/browser/ui/toolbar", "//ios/chrome/browser/ui/toolbar",
"//ios/chrome/browser/ui/toolbar/public:feature_flags", "//ios/chrome/browser/ui/toolbar/public:feature_flags",
"//ios/chrome/browser/ui/util", "//ios/chrome/browser/ui/util",
......
...@@ -7,15 +7,15 @@ ...@@ -7,15 +7,15 @@
#include "base/logging.h" #include "base/logging.h"
#import "ios/chrome/browser/ui/commands/browser_commands.h" #import "ios/chrome/browser/ui/commands/browser_commands.h"
#import "ios/chrome/browser/ui/commands/command_dispatcher.h" #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
#import "ios/chrome/browser/ui/qr_scanner/qr_scanner_presenting.h"
#import "ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller.h" #import "ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller.h"
#import "ios/chrome/browser/ui/scanner/scanner_presenting.h"
#import "ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h" #import "ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h"
#if !defined(__has_feature) || !__has_feature(objc_arc) #if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support." #error "This file requires ARC support."
#endif #endif
@interface QRScannerLegacyCoordinator ()<QRScannerPresenting> @interface QRScannerLegacyCoordinator () <ScannerPresenting>
@property(nonatomic, readwrite, strong) QRScannerViewController* viewController; @property(nonatomic, readwrite, strong) QRScannerViewController* viewController;
...@@ -71,8 +71,8 @@ ...@@ -71,8 +71,8 @@
#pragma mark - QRScannerPresenting #pragma mark - QRScannerPresenting
- (void)dismissQRScannerViewController:(UIViewController*)controller - (void)dismissScannerViewController:(UIViewController*)controller
completion:(void (^)(void))completion { completion:(void (^)(void))completion {
DCHECK_EQ(self.viewController, DCHECK_EQ(self.viewController,
self.baseViewController.presentedViewController); self.baseViewController.presentedViewController);
[self.baseViewController dismissViewControllerAnimated:YES [self.baseViewController dismissViewControllerAnimated:YES
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_QR_SCANNER_QR_SCANNER_TRANSITIONING_DELEGATE_H_
#define IOS_CHROME_BROWSER_UI_QR_SCANNER_QR_SCANNER_TRANSITIONING_DELEGATE_H_
#import <UIKit/UIKit.h>
@interface QRScannerTransitioningDelegate
: NSObject<UIViewControllerTransitioningDelegate>
@end
#endif // IOS_CHROME_BROWSER_UI_QR_SCANNER_QR_SCANNER_TRANSITIONING_DELEGATE_H_
// Copyright 2016 The Chromium Authors. All rights reserved. // Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_QR_SCANNER_QR_SCANNER_VIEW_CONTROLLER_H_ #ifndef IOS_CHROME_BROWSER_UI_QR_SCANNER_QR_SCANNER_VIEW_CONTROLLER_H_
#define IOS_CHROME_BROWSER_UI_QR_SCANNER_QR_SCANNER_VIEW_CONTROLLER_H_ #define IOS_CHROME_BROWSER_UI_QR_SCANNER_QR_SCANNER_VIEW_CONTROLLER_H_
#import <UIKit/UIKit.h> #import "ios/chrome/browser/ui/scanner/scanner_view_controller.h"
#include "ios/chrome/browser/ui/qr_scanner/camera_controller.h"
#include "ios/chrome/browser/ui/qr_scanner/qr_scanner_view.h"
@protocol LoadQueryCommands; @protocol LoadQueryCommands;
@protocol QRScannerPresenting;
// View controller for the QR scanner. // View controller for the QR Scanner.
@interface QRScannerViewController @interface QRScannerViewController : ScannerViewController
: UIViewController <CameraControllerDelegate, ScannerViewDelegate>
- (instancetype)initWithPresentationProvider: - (instancetype)initWithPresentationProvider:
(id<QRScannerPresenting>)presentationProvider (id<ScannerPresenting>)presentationProvider
queryLoader:(id<LoadQueryCommands>)queryLoader queryLoader:(id<LoadQueryCommands>)queryLoader
NS_DESIGNATED_INITIALIZER; NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithPresentationProvider:
(id<ScannerPresenting>)presentationProvider
cameraController:(CameraController*)cameraController
NS_UNAVAILABLE;
- (instancetype)initWithNibName:(NSString*)name - (instancetype)initWithNibName:(NSString*)name
bundle:(NSBundle*)bundle NS_UNAVAILABLE; bundle:(NSBundle*)bundle NS_UNAVAILABLE;
- (instancetype)initWithCoder:(NSCoder*)coder NS_UNAVAILABLE; - (instancetype)initWithCoder:(NSCoder*)coder NS_UNAVAILABLE;
// Returns a view controller to be presented based on the camera state. Returns
// |self| if the camera is available or an appropriate UIAlertController if
// there was an error loading the camera.
- (UIViewController*)getViewControllerToPresent;
// Builds a scanner view overlay. Can be overridden by a subclass.
- (QRScannerView*)scannerView;
@end @end
#endif // IOS_CHROME_BROWSER_UI_QR_SCANNER_QR_SCANNER_VIEW_CONTROLLER_H_ #endif // IOS_CHROME_BROWSER_UI_QR_SCANNER_QR_SCANNER_VIEW_CONTROLLER_H_
// Copyright 2016 The Chromium Authors. All rights reserved. // Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#import "ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller.h" #import "ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller.h"
#import <AVFoundation/AVFoundation.h>
#include "base/logging.h" #include "base/logging.h"
#include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h" #include "base/metrics/user_metrics_action.h"
#include "ios/chrome/browser/ui/commands/load_query_commands.h" #include "ios/chrome/browser/ui/commands/load_query_commands.h"
#include "ios/chrome/browser/ui/qr_scanner/qr_scanner_alerts.h"
#include "ios/chrome/browser/ui/qr_scanner/qr_scanner_presenting.h"
#include "ios/chrome/browser/ui/qr_scanner/qr_scanner_transitioning_delegate.h"
#include "ios/chrome/browser/ui/qr_scanner/qr_scanner_view.h" #include "ios/chrome/browser/ui/qr_scanner/qr_scanner_view.h"
#include "ios/chrome/browser/ui/scanner/scanner_alerts.h"
#include "ios/chrome/browser/ui/scanner/scanner_presenting.h"
#include "ios/chrome/browser/ui/scanner/scanner_transitioning_delegate.h"
#include "ios/chrome/browser/ui/scanner/scanner_view.h"
#include "ios/chrome/grit/ios_strings.h" #include "ios/chrome/grit/ios_strings.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
...@@ -23,363 +22,60 @@ ...@@ -23,363 +22,60 @@
using base::UserMetricsAction; using base::UserMetricsAction;
namespace {
// The reason why the QRScannerViewController was dismissed. Used for collecting
// metrics.
enum DismissalReason {
CLOSE_BUTTON,
ERROR_DIALOG,
SCANNED_CODE,
// Not reported. Should be kept last of enum.
IMPOSSIBLY_UNLIKELY_AUTHORIZATION_CHANGE
};
} // namespace
@interface QRScannerViewController () { @interface QRScannerViewController () {
// The CameraController managing the camera connection.
CameraController* _cameraController;
// The view displaying the QR scanner.
QRScannerView* _qrScannerView;
// The scanned result. // The scanned result.
NSString* _result; NSString* _result;
// Whether the scanned result should be immediately loaded. // Whether the scanned result should be immediately loaded.
BOOL _loadResultImmediately; BOOL _loadResultImmediately;
// The transitioning delegate used for presenting and dismissing the QR // The transitioning delegate used for presenting and dismissing the QR
// scanner. // scanner.
QRScannerTransitioningDelegate* _transitioningDelegate; ScannerTransitioningDelegate* _transitioningDelegate;
} }
@property(nonatomic, readwrite, weak) id<QRScannerPresenting>
presentationProvider;
@property(nonatomic, readwrite, weak) id<LoadQueryCommands> queryLoader; @property(nonatomic, readwrite, weak) id<LoadQueryCommands> queryLoader;
// Dismisses the QRScannerViewController and runs |completion| on completion.
// Logs metrics according to the |reason| for dismissal.
- (void)dismissForReason:(DismissalReason)reason
withCompletion:(void (^)(void))completion;
// Starts receiving notifications about the UIApplication going to background.
- (void)startReceivingNotifications;
// Stops receiving all notificatins.
- (void)stopReceivingNotifications;
// Requests the torch mode to be set to |mode| by the |_cameraController| and
// the icon of the torch button to be changed by the |_qrScannerView|.
- (void)setTorchMode:(AVCaptureTorchMode)mode;
// Stops recording when the application resigns active.
- (void)handleUIApplicationWillResignActiveNotification;
// Dismisses the QR scanner and passes the scanned result to the delegate when
// the accessibility announcement for scanned QR code finishes.
- (void)handleUIAccessibilityAnnouncementDidFinishNotification:
(NSNotification*)notification;
@end @end
@implementation QRScannerViewController @implementation QRScannerViewController
@synthesize queryLoader = _queryLoader; #pragma mark Lifecycle
@synthesize presentationProvider = _presentationProvider;
#pragma mark - Lifecycle
- (instancetype) - (instancetype)
initWithPresentationProvider:(id<QRScannerPresenting>)presentationProvider initWithPresentationProvider:(id<ScannerPresenting>)presentationProvider
queryLoader:(id<LoadQueryCommands>)queryLoader { queryLoader:(id<LoadQueryCommands>)queryLoader {
self = [super initWithNibName:nil bundle:nil]; self = [super
initWithPresentationProvider:presentationProvider
cameraController:[CameraController
cameraControllerWithDelegate:self]];
if (self) { if (self) {
_queryLoader = queryLoader; _queryLoader = queryLoader;
_presentationProvider = presentationProvider;
_cameraController = [CameraController cameraControllerWithDelegate:self];
} }
return self; return self;
} }
- (instancetype)initWithNibName:(NSString*)name bundle:(NSBundle*)bundle { #pragma mark - ScannerViewController
NOTREACHED();
return nil;
}
- (instancetype)initWithCoder:(NSCoder*)coder {
NOTREACHED();
return nil;
}
#pragma mark - UIAccessibilityAction
- (BOOL)accessibilityPerformEscape {
[self dismissForReason:CLOSE_BUTTON withCompletion:nil];
return YES;
}
#pragma mark - UIViewController
- (void)viewDidLoad {
[super viewDidLoad];
DCHECK(_cameraController);
_qrScannerView = [self scannerView];
[self.view addSubview:_qrScannerView];
// Constraints for |_qrScannerView|.
[_qrScannerView setTranslatesAutoresizingMaskIntoConstraints:NO];
[NSLayoutConstraint activateConstraints:@[
[[_qrScannerView leadingAnchor]
constraintEqualToAnchor:[self.view leadingAnchor]],
[[_qrScannerView trailingAnchor]
constraintEqualToAnchor:[self.view trailingAnchor]],
[[_qrScannerView topAnchor] constraintEqualToAnchor:[self.view topAnchor]],
[[_qrScannerView bottomAnchor]
constraintEqualToAnchor:[self.view bottomAnchor]],
]];
AVCaptureVideoPreviewLayer* previewLayer = [_qrScannerView getPreviewLayer];
switch ([_cameraController getAuthorizationStatus]) {
case AVAuthorizationStatusNotDetermined:
[_cameraController
requestAuthorizationAndLoadCaptureSession:previewLayer];
break;
case AVAuthorizationStatusAuthorized:
[_cameraController loadCaptureSession:previewLayer];
break;
case AVAuthorizationStatusRestricted:
case AVAuthorizationStatusDenied:
// If this happens, then the user is really unlucky:
// The authorization status changed in between the moment this VC was
// instantiated and presented, and the moment viewDidLoad was called.
[self dismissForReason:IMPOSSIBLY_UNLIKELY_AUTHORIZATION_CHANGE
withCompletion:nil];
break;
}
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self startReceivingNotifications];
[_cameraController startRecording];
// Reset torch.
[self setTorchMode:AVCaptureTorchModeOff];
}
- (void)viewWillTransitionToSize:(CGSize)size - (ScannerView*)buildScannerView {
withTransitionCoordinator:
(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
CGFloat epsilon = 0.0001;
// Note: targetTransform is always either identity or a 90, -90, or 180 degree
// rotation.
CGAffineTransform targetTransform = coordinator.targetTransform;
CGFloat angle = atan2f(targetTransform.b, targetTransform.a);
if (fabs(angle) > epsilon) {
// Rotate the preview in the opposite direction of the interface rotation
// and add a small value to the angle to force the rotation to occur in the
// correct direction when rotating by 180 degrees.
void (^animationBlock)(id<UIViewControllerTransitionCoordinatorContext>) =
^void(id<UIViewControllerTransitionCoordinatorContext> context) {
[_qrScannerView rotatePreviewByAngle:(epsilon - angle)];
};
// Note: The completion block is called even if the animation is
// interrupted, for example by pressing the home button, with the same
// target transform as the animation block.
void (^completionBlock)(id<UIViewControllerTransitionCoordinatorContext>) =
^void(id<UIViewControllerTransitionCoordinatorContext> context) {
[_qrScannerView finishPreviewRotation];
};
[coordinator animateAlongsideTransition:animationBlock
completion:completionBlock];
} else if (!CGSizeEqualToSize(self.view.frame.size, size)) {
// Reset the size of the preview if the bounds of the view controller
// changed. This can happen if entering or leaving Split View mode on iPad.
[_qrScannerView resetPreviewFrame:size];
[_cameraController resetVideoOrientation:[_qrScannerView getPreviewLayer]];
}
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[_cameraController stopRecording];
[self stopReceivingNotifications];
// Reset torch.
[self setTorchMode:AVCaptureTorchModeOff];
}
- (BOOL)prefersStatusBarHidden {
return YES;
}
#pragma mark - Public methods
- (UIViewController*)getViewControllerToPresent {
DCHECK(_cameraController);
switch ([_cameraController getAuthorizationStatus]) {
case AVAuthorizationStatusNotDetermined:
case AVAuthorizationStatusAuthorized:
_transitioningDelegate = [[QRScannerTransitioningDelegate alloc] init];
[self setTransitioningDelegate:_transitioningDelegate];
return self;
case AVAuthorizationStatusRestricted:
case AVAuthorizationStatusDenied:
return qr_scanner::DialogForCameraState(
qr_scanner::CAMERA_PERMISSION_DENIED, nil);
}
}
- (QRScannerView*)scannerView {
return [[QRScannerView alloc] initWithFrame:self.view.frame delegate:self]; return [[QRScannerView alloc] initWithFrame:self.view.frame delegate:self];
} }
#pragma mark - Private methods - (void)dismissForReason:(scannerViewController::DismissalReason)reason
- (void)dismissForReason:(DismissalReason)reason
withCompletion:(void (^)(void))completion { withCompletion:(void (^)(void))completion {
switch (reason) { switch (reason) {
case CLOSE_BUTTON: case scannerViewController::CLOSE_BUTTON:
base::RecordAction(UserMetricsAction("MobileQRScannerClose")); base::RecordAction(UserMetricsAction("MobileQRScannerClose"));
break; break;
case ERROR_DIALOG: case scannerViewController::ERROR_DIALOG:
base::RecordAction(UserMetricsAction("MobileQRScannerError")); base::RecordAction(UserMetricsAction("MobileQRScannerError"));
break; break;
case SCANNED_CODE: case scannerViewController::SCANNED_CODE:
base::RecordAction(UserMetricsAction("MobileQRScannerScannedCode")); base::RecordAction(UserMetricsAction("MobileQRScannerScannedCode"));
break; break;
case IMPOSSIBLY_UNLIKELY_AUTHORIZATION_CHANGE: case scannerViewController::IMPOSSIBLY_UNLIKELY_AUTHORIZATION_CHANGE:
break; break;
} }
[self.presentationProvider dismissQRScannerViewController:self [super dismissForReason:reason withCompletion:completion];
completion:completion];
}
- (void)startReceivingNotifications {
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleUIApplicationWillResignActiveNotification)
name:UIApplicationWillResignActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(
handleUIAccessibilityAnnouncementDidFinishNotification:)
name:UIAccessibilityAnnouncementDidFinishNotification
object:nil];
}
- (void)stopReceivingNotifications {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)setTorchMode:(AVCaptureTorchMode)mode {
[_cameraController setTorchMode:mode];
}
#pragma mark - Notification handlers
- (void)handleUIApplicationWillResignActiveNotification {
[self setTorchMode:AVCaptureTorchModeOff];
}
- (void)handleUIAccessibilityAnnouncementDidFinishNotification:
(NSNotification*)notification {
NSString* announcement = [[notification userInfo]
valueForKey:UIAccessibilityAnnouncementKeyStringValue];
if ([announcement
isEqualToString:
l10n_util::GetNSString(
IDS_IOS_QR_SCANNER_CODE_SCANNED_ACCESSIBILITY_ANNOUNCEMENT)]) {
DCHECK(_result);
[self dismissForReason:SCANNED_CODE
withCompletion:^{
[self.queryLoader loadQuery:_result
immediately:_loadResultImmediately];
}];
}
}
#pragma mark - CameraControllerDelegate
- (void)captureSessionIsConnected {
[_cameraController setViewport:[_qrScannerView viewportRectOfInterest]];
}
- (void)cameraStateChanged:(qr_scanner::CameraState)state {
switch (state) {
case qr_scanner::CAMERA_AVAILABLE:
// Dismiss any presented alerts.
if ([self presentedViewController]) {
[self dismissViewControllerAnimated:YES completion:nil];
}
break;
case qr_scanner::CAMERA_IN_USE_BY_ANOTHER_APPLICATION:
case qr_scanner::MULTIPLE_FOREGROUND_APPS:
case qr_scanner::CAMERA_PERMISSION_DENIED:
case qr_scanner::CAMERA_UNAVAILABLE_DUE_TO_SYSTEM_PRESSURE:
case qr_scanner::CAMERA_UNAVAILABLE: {
// Dismiss any presented alerts.
if ([self presentedViewController]) {
[self dismissViewControllerAnimated:YES completion:nil];
}
[self presentViewController:qr_scanner::DialogForCameraState(
state,
^(UIAlertAction*) {
[self dismissForReason:ERROR_DIALOG
withCompletion:nil];
})
animated:YES
completion:nil];
break;
}
case qr_scanner::CAMERA_NOT_LOADED:
NOTREACHED();
break;
}
}
- (void)torchStateChanged:(BOOL)torchIsOn {
[_qrScannerView setTorchButtonTo:torchIsOn];
}
- (void)torchAvailabilityChanged:(BOOL)torchIsAvailable {
[_qrScannerView enableTorchButton:torchIsAvailable];
}
- (void)receiveQRScannerResult:(NSString*)result loadImmediately:(BOOL)load {
if (UIAccessibilityIsVoiceOverRunning()) {
// Post a notification announcing that a code was scanned. QR scanner will
// be dismissed when the UIAccessibilityAnnouncementDidFinishNotification is
// received.
_result = [result copy];
_loadResultImmediately = load;
UIAccessibilityPostNotification(
UIAccessibilityAnnouncementNotification,
l10n_util::GetNSString(
IDS_IOS_QR_SCANNER_CODE_SCANNED_ACCESSIBILITY_ANNOUNCEMENT));
} else {
[_qrScannerView animateScanningResultWithCompletion:^void(void) {
[self dismissForReason:SCANNED_CODE
withCompletion:^{
[self.queryLoader loadQuery:result immediately:load];
}];
}];
}
}
#pragma mark - ScannerViewDelegate
- (void)dismissScannerView:(id)sender {
[self dismissForReason:CLOSE_BUTTON withCompletion:nil];
}
- (void)toggleTorch:(id)sender {
if ([_cameraController isTorchActive]) {
[self setTorchMode:AVCaptureTorchModeOff];
} else {
base::RecordAction(UserMetricsAction("MobileQRScannerTorchOn"));
[self setTorchMode:AVCaptureTorchModeOn];
}
} }
@end @end
...@@ -16,9 +16,9 @@ ...@@ -16,9 +16,9 @@
#import "ios/chrome/browser/ui/location_bar/location_bar_coordinator.h" #import "ios/chrome/browser/ui/location_bar/location_bar_coordinator.h"
#import "ios/chrome/browser/ui/location_bar/location_bar_url_loader.h" #import "ios/chrome/browser/ui/location_bar/location_bar_url_loader.h"
#include "ios/chrome/browser/ui/omnibox/location_bar_delegate.h" #include "ios/chrome/browser/ui/omnibox/location_bar_delegate.h"
#include "ios/chrome/browser/ui/qr_scanner/camera_controller.h"
#include "ios/chrome/browser/ui/qr_scanner/qr_scanner_view.h" #include "ios/chrome/browser/ui/qr_scanner/qr_scanner_view.h"
#include "ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller.h" #include "ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller.h"
#include "ios/chrome/browser/ui/scanner/camera_controller.h"
#import "ios/chrome/browser/ui/toolbar/public/features.h" #import "ios/chrome/browser/ui/toolbar/public/features.h"
#include "ios/chrome/browser/ui/util/ui_util.h" #include "ios/chrome/browser/ui/util/ui_util.h"
#import "ios/chrome/browser/url_loading/url_loading_params.h" #import "ios/chrome/browser/url_loading/url_loading_params.h"
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
#endif #endif
using namespace chrome_test_util; using namespace chrome_test_util;
using namespace qr_scanner; using namespace scanner;
namespace { namespace {
...@@ -380,7 +380,7 @@ void TapKeyboardReturnKeyInOmniboxWithText(std::string text) { ...@@ -380,7 +380,7 @@ void TapKeyboardReturnKeyInOmniboxWithText(std::string text) {
IDS_IOS_QR_SCANNER_CAMERA_IN_USE_ALERT_TITLE); IDS_IOS_QR_SCANNER_CAMERA_IN_USE_ALERT_TITLE);
case CAMERA_PERMISSION_DENIED: case CAMERA_PERMISSION_DENIED:
return l10n_util::GetNSString( return l10n_util::GetNSString(
IDS_IOS_QR_SCANNER_CAMERA_PERMISSIONS_HELP_TITLE_GO_TO_SETTINGS); IDS_IOS_SCANNER_CAMERA_PERMISSIONS_HELP_TITLE_GO_TO_SETTINGS);
case CAMERA_UNAVAILABLE_DUE_TO_SYSTEM_PRESSURE: case CAMERA_UNAVAILABLE_DUE_TO_SYSTEM_PRESSURE:
case CAMERA_UNAVAILABLE: case CAMERA_UNAVAILABLE:
return l10n_util::GetNSString( return l10n_util::GetNSString(
......
...@@ -5,10 +5,19 @@ ...@@ -5,10 +5,19 @@
source_set("scanner") { source_set("scanner") {
configs += [ "//build/config/compiler:enable_arc" ] configs += [ "//build/config/compiler:enable_arc" ]
sources = [ sources = [
"camera_controller.h",
"camera_controller.mm",
"preview_overlay_view.h", "preview_overlay_view.h",
"preview_overlay_view.mm", "preview_overlay_view.mm",
"scanner_alerts.h",
"scanner_alerts.mm",
"scanner_presenting.h",
"scanner_transitioning_delegate.h",
"scanner_transitioning_delegate.mm",
"scanner_view.h", "scanner_view.h",
"scanner_view.mm", "scanner_view.mm",
"scanner_view_controller.h",
"scanner_view_controller.mm",
"video_preview_view.h", "video_preview_view.h",
"video_preview_view.mm", "video_preview_view.mm",
] ]
......
...@@ -2,15 +2,15 @@ ...@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_QR_SCANNER_CAMERA_CONTROLLER_H_ #ifndef IOS_CHROME_BROWSER_UI_SCANNER_CAMERA_CONTROLLER_H_
#define IOS_CHROME_BROWSER_UI_QR_SCANNER_CAMERA_CONTROLLER_H_ #define IOS_CHROME_BROWSER_UI_SCANNER_CAMERA_CONTROLLER_H_
#import <AVFoundation/AVFoundation.h> #import <AVFoundation/AVFoundation.h>
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#include "base/ios/block_types.h" #include "base/ios/block_types.h"
namespace qr_scanner { namespace scanner {
// Values to distinguish between different camera states to display the correct // Values to distinguish between different camera states to display the correct
// view controller or system alert. // view controller or system alert.
...@@ -38,7 +38,7 @@ enum CameraState { ...@@ -38,7 +38,7 @@ enum CameraState {
CAMERA_NOT_LOADED, CAMERA_NOT_LOADED,
}; };
} // namespace qr_scanner } // namespace scanner
@protocol CameraControllerDelegate @protocol CameraControllerDelegate
...@@ -46,7 +46,7 @@ enum CameraState { ...@@ -46,7 +46,7 @@ enum CameraState {
// preview. // preview.
- (void)captureSessionIsConnected; - (void)captureSessionIsConnected;
// Called on the main queue when the camera state changes. // Called on the main queue when the camera state changes.
- (void)cameraStateChanged:(qr_scanner::CameraState)state; - (void)cameraStateChanged:(scanner::CameraState)state;
// Called on the main queue when the torch state changes. // Called on the main queue when the torch state changes.
- (void)torchStateChanged:(BOOL)torchIsOn; - (void)torchStateChanged:(BOOL)torchIsOn;
// Called on the main queue when the torch availability changes. // Called on the main queue when the torch availability changes.
...@@ -109,4 +109,4 @@ enum CameraState { ...@@ -109,4 +109,4 @@ enum CameraState {
@end @end
#endif // IOS_CHROME_BROWSER_UI_QR_SCANNER_CAMERA_CONTROLLER_H_ #endif // IOS_CHROME_BROWSER_UI_SCANNER_CAMERA_CONTROLLER_H_
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#import "ios/chrome/browser/ui/qr_scanner/camera_controller.h" #import "ios/chrome/browser/ui/scanner/camera_controller.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/mac/foundation_util.h" #include "base/mac/foundation_util.h"
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#error "This file requires ARC support." #error "This file requires ARC support."
#endif #endif
@interface CameraController ()<AVCaptureMetadataOutputObjectsDelegate> { @interface CameraController () <AVCaptureMetadataOutputObjectsDelegate> {
// The queue for dispatching calls to |_captureSession|. // The queue for dispatching calls to |_captureSession|.
dispatch_queue_t _sessionQueue; dispatch_queue_t _sessionQueue;
} }
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
@property(nonatomic, readwrite, weak) id<CameraControllerDelegate> delegate; @property(nonatomic, readwrite, weak) id<CameraControllerDelegate> delegate;
// The current state of the camera. The state is set to CAMERA_NOT_LOADED before // The current state of the camera. The state is set to CAMERA_NOT_LOADED before
// the camera is first loaded, and afterwards it is never CAMERA_NOT_LOADED. // the camera is first loaded, and afterwards it is never CAMERA_NOT_LOADED.
@property(nonatomic, readwrite, assign) qr_scanner::CameraState cameraState; @property(nonatomic, readwrite, assign) scanner::CameraState cameraState;
// Redeclaration of |torchActive| to make the setter private. // Redeclaration of |torchActive| to make the setter private.
@property(nonatomic, readwrite, assign, getter=isTorchActive) BOOL torchActive; @property(nonatomic, readwrite, assign, getter=isTorchActive) BOOL torchActive;
// The current availability of the torch. // The current availability of the torch.
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
@implementation CameraController @implementation CameraController
#pragma mark lifecycle #pragma mark - Lifecycle
+ (instancetype)cameraControllerWithDelegate: + (instancetype)cameraControllerWithDelegate:
(id<CameraControllerDelegate>)delegate { (id<CameraControllerDelegate>)delegate {
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
self = [super init]; self = [super init];
if (self) { if (self) {
DCHECK(delegate); DCHECK(delegate);
_cameraState = qr_scanner::CAMERA_NOT_LOADED; _cameraState = scanner::CAMERA_NOT_LOADED;
_delegate = delegate; _delegate = delegate;
std::string queueName = std::string queueName =
base::StringPrintf("%s.chrome.ios.QRScannerCaptureSessionQueue", base::StringPrintf("%s.chrome.ios.QRScannerCaptureSessionQueue",
...@@ -90,7 +90,7 @@ ...@@ -90,7 +90,7 @@
[self stopReceivingNotifications]; [self stopReceivingNotifications];
} }
#pragma mark public methods #pragma mark - Public methods
- (AVAuthorizationStatus)getAuthorizationStatus { - (AVAuthorizationStatus)getAuthorizationStatus {
return [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; return [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
...@@ -105,8 +105,7 @@ ...@@ -105,8 +105,7 @@
requestAccessForMediaType:AVMediaTypeVideo requestAccessForMediaType:AVMediaTypeVideo
completionHandler:^void(BOOL granted) { completionHandler:^void(BOOL granted) {
if (!granted) { if (!granted) {
[weakSelf [weakSelf setCameraState:scanner::CAMERA_PERMISSION_DENIED];
setCameraState:qr_scanner::CAMERA_PERMISSION_DENIED];
} else { } else {
[weakSelf loadCaptureSession:previewLayer]; [weakSelf loadCaptureSession:previewLayer];
} }
...@@ -186,15 +185,15 @@ ...@@ -186,15 +185,15 @@
}); });
} }
#pragma mark private methods #pragma mark - Private methods
- (BOOL)isCameraAvailable { - (BOOL)isCameraAvailable {
return [self cameraState] == qr_scanner::CAMERA_AVAILABLE; return [self cameraState] == scanner::CAMERA_AVAILABLE;
} }
- (void)loadCaptureSession:(AVCaptureVideoPreviewLayer*)previewLayer { - (void)loadCaptureSession:(AVCaptureVideoPreviewLayer*)previewLayer {
DCHECK(previewLayer); DCHECK(previewLayer);
DCHECK([self cameraState] == qr_scanner::CAMERA_NOT_LOADED); DCHECK([self cameraState] == scanner::CAMERA_NOT_LOADED);
DCHECK([self getAuthorizationStatus] == AVAuthorizationStatusAuthorized); DCHECK([self getAuthorizationStatus] == AVAuthorizationStatusAuthorized);
__weak CameraController* weakSelf = self; __weak CameraController* weakSelf = self;
dispatch_async(_sessionQueue, ^{ dispatch_async(_sessionQueue, ^{
...@@ -213,7 +212,7 @@ ...@@ -213,7 +212,7 @@
position:AVCaptureDevicePositionBack]; position:AVCaptureDevicePositionBack];
videoCaptureDevices = [discoverySession devices]; videoCaptureDevices = [discoverySession devices];
if ([videoCaptureDevices count] == 0) { if ([videoCaptureDevices count] == 0) {
[self setCameraState:qr_scanner::CAMERA_UNAVAILABLE]; [self setCameraState:scanner::CAMERA_UNAVAILABLE];
return; return;
} }
...@@ -225,7 +224,7 @@ ...@@ -225,7 +224,7 @@
// Allow only the back camera. // Allow only the back camera.
if (cameraIndex == NSNotFound) { if (cameraIndex == NSNotFound) {
[self setCameraState:qr_scanner::CAMERA_UNAVAILABLE]; [self setCameraState:scanner::CAMERA_UNAVAILABLE];
return; return;
} }
AVCaptureDevice* camera = videoCaptureDevices[cameraIndex]; AVCaptureDevice* camera = videoCaptureDevices[cameraIndex];
...@@ -235,13 +234,13 @@ ...@@ -235,13 +234,13 @@
AVCaptureDeviceInput* videoInput = AVCaptureDeviceInput* videoInput =
[AVCaptureDeviceInput deviceInputWithDevice:camera error:&error]; [AVCaptureDeviceInput deviceInputWithDevice:camera error:&error];
if (error || !videoInput) { if (error || !videoInput) {
[self setCameraState:qr_scanner::CAMERA_UNAVAILABLE]; [self setCameraState:scanner::CAMERA_UNAVAILABLE];
return; return;
} }
AVCaptureSession* session = [[AVCaptureSession alloc] init]; AVCaptureSession* session = [[AVCaptureSession alloc] init];
if (![session canAddInput:videoInput]) { if (![session canAddInput:videoInput]) {
[self setCameraState:qr_scanner::CAMERA_UNAVAILABLE]; [self setCameraState:scanner::CAMERA_UNAVAILABLE];
return; return;
} }
[session addInput:videoInput]; [session addInput:videoInput];
...@@ -252,7 +251,7 @@ ...@@ -252,7 +251,7 @@
[metadataOutput setMetadataObjectsDelegate:self [metadataOutput setMetadataObjectsDelegate:self
queue:dispatch_get_main_queue()]; queue:dispatch_get_main_queue()];
if (![session canAddOutput:metadataOutput]) { if (![session canAddOutput:metadataOutput]) {
[self setCameraState:qr_scanner::CAMERA_UNAVAILABLE]; [self setCameraState:scanner::CAMERA_UNAVAILABLE];
return; return;
} }
[session addOutput:metadataOutput]; [session addOutput:metadataOutput];
...@@ -260,14 +259,14 @@ ...@@ -260,14 +259,14 @@
// Require QR code recognition to be available. // Require QR code recognition to be available.
if (![availableCodeTypes containsObject:AVMetadataObjectTypeQRCode]) { if (![availableCodeTypes containsObject:AVMetadataObjectTypeQRCode]) {
[self setCameraState:qr_scanner::CAMERA_UNAVAILABLE]; [self setCameraState:scanner::CAMERA_UNAVAILABLE];
return; return;
} }
[metadataOutput setMetadataObjectTypes:availableCodeTypes]; [metadataOutput setMetadataObjectTypes:availableCodeTypes];
_metadataOutput = metadataOutput; _metadataOutput = metadataOutput;
_captureSession = session; _captureSession = session;
[self setCameraState:qr_scanner::CAMERA_AVAILABLE]; [self setCameraState:scanner::CAMERA_AVAILABLE];
// Setup torchAvailable. // Setup torchAvailable.
[self setTorchAvailable:[camera hasTorch] && [self setTorchAvailable:[camera hasTorch] &&
[camera isTorchModeSupported:AVCaptureTorchModeOn] && [camera isTorchModeSupported:AVCaptureTorchModeOn] &&
...@@ -365,12 +364,12 @@ ...@@ -365,12 +364,12 @@
} }
} }
#pragma mark notification handlers #pragma mark - Notification Handlers
- (void)handleAVCaptureSessionRuntimeError:(NSNotification*)notification { - (void)handleAVCaptureSessionRuntimeError:(NSNotification*)notification {
__weak CameraController* weakSelf = self; __weak CameraController* weakSelf = self;
dispatch_async(_sessionQueue, ^{ dispatch_async(_sessionQueue, ^{
[weakSelf setCameraState:qr_scanner::CAMERA_UNAVAILABLE]; [weakSelf setCameraState:scanner::CAMERA_UNAVAILABLE];
}); });
} }
...@@ -386,15 +385,14 @@ ...@@ -386,15 +385,14 @@
// is backgrounded and foregrounded. // is backgrounded and foregrounded.
break; break;
case AVCaptureSessionInterruptionReasonVideoDeviceInUseByAnotherClient: case AVCaptureSessionInterruptionReasonVideoDeviceInUseByAnotherClient:
[weakSelf [weakSelf setCameraState:scanner::CAMERA_IN_USE_BY_ANOTHER_APPLICATION];
setCameraState:qr_scanner::CAMERA_IN_USE_BY_ANOTHER_APPLICATION];
break; break;
case AVCaptureSessionInterruptionReasonVideoDeviceNotAvailableWithMultipleForegroundApps: case AVCaptureSessionInterruptionReasonVideoDeviceNotAvailableWithMultipleForegroundApps:
[weakSelf setCameraState:qr_scanner::MULTIPLE_FOREGROUND_APPS]; [weakSelf setCameraState:scanner::MULTIPLE_FOREGROUND_APPS];
break; break;
case AVCaptureSessionInterruptionReasonVideoDeviceNotAvailableDueToSystemPressure: case AVCaptureSessionInterruptionReasonVideoDeviceNotAvailableDueToSystemPressure:
[weakSelf setCameraState:qr_scanner:: [weakSelf
CAMERA_UNAVAILABLE_DUE_TO_SYSTEM_PRESSURE]; setCameraState:scanner::CAMERA_UNAVAILABLE_DUE_TO_SYSTEM_PRESSURE];
break; break;
case AVCaptureSessionInterruptionReasonAudioDeviceInUseByAnotherClient: case AVCaptureSessionInterruptionReasonAudioDeviceInUseByAnotherClient:
NOTREACHED(); NOTREACHED();
...@@ -408,7 +406,7 @@ ...@@ -408,7 +406,7 @@
dispatch_async(_sessionQueue, ^{ dispatch_async(_sessionQueue, ^{
CameraController* strongSelf = weakSelf; CameraController* strongSelf = weakSelf;
if (strongSelf && [strongSelf.captureSession isRunning]) { if (strongSelf && [strongSelf.captureSession isRunning]) {
[strongSelf setCameraState:qr_scanner::CAMERA_AVAILABLE]; [strongSelf setCameraState:scanner::CAMERA_AVAILABLE];
} }
}); });
} }
...@@ -416,7 +414,7 @@ ...@@ -416,7 +414,7 @@
- (void)handleAVCaptureDeviceWasDisconnected:(NSNotification*)notification { - (void)handleAVCaptureDeviceWasDisconnected:(NSNotification*)notification {
__weak CameraController* weakSelf = self; __weak CameraController* weakSelf = self;
dispatch_async(_sessionQueue, ^{ dispatch_async(_sessionQueue, ^{
[weakSelf setCameraState:qr_scanner::CAMERA_UNAVAILABLE]; [weakSelf setCameraState:scanner::CAMERA_UNAVAILABLE];
}); });
} }
...@@ -433,9 +431,9 @@ ...@@ -433,9 +431,9 @@
} }
} }
#pragma mark property implementation #pragma mark - Property Implementation
- (void)setCameraState:(qr_scanner::CameraState)state { - (void)setCameraState:(scanner::CameraState)state {
if (state == _cameraState) { if (state == _cameraState) {
return; return;
} }
...@@ -468,7 +466,7 @@ ...@@ -468,7 +466,7 @@
}); });
} }
#pragma mark AVCaptureMetadataOutputObjectsDelegate #pragma mark - AVCaptureMetadataOutputObjectsDelegate
- (void)captureOutput:(AVCaptureOutput*)captureOutput - (void)captureOutput:(AVCaptureOutput*)captureOutput
didOutputMetadataObjects:(NSArray*)metadataObjects didOutputMetadataObjects:(NSArray*)metadataObjects
......
...@@ -105,7 +105,7 @@ const CGFloat kViewportBorderShadowRadius = 10.0; ...@@ -105,7 +105,7 @@ const CGFloat kViewportBorderShadowRadius = 10.0;
[_viewportBorder setMask:[self viewportBorderMaskWithFrameSize:frameSize]]; [_viewportBorder setMask:[self viewportBorderMaskWithFrameSize:frameSize]];
} }
#pragma mark Private #pragma mark - Private
// Creates a square mask for the overlay to keep the viewport transparent. // Creates a square mask for the overlay to keep the viewport transparent.
- (CAShapeLayer*)viewportMaskWithFrameSize:(CGSize)frameSize { - (CAShapeLayer*)viewportMaskWithFrameSize:(CGSize)frameSize {
......
...@@ -2,15 +2,14 @@ ...@@ -2,15 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_QR_SCANNER_QR_SCANNER_ALERTS_H_ #ifndef IOS_CHROME_BROWSER_UI_SCANNER_SCANNER_ALERTS_H_
#define IOS_CHROME_BROWSER_UI_QR_SCANNER_QR_SCANNER_ALERTS_H_ #define IOS_CHROME_BROWSER_UI_SCANNER_SCANNER_ALERTS_H_
#include "ios/chrome/browser/ui/qr_scanner/camera_controller.h" #include "ios/chrome/browser/ui/scanner/camera_controller.h"
@class UIAlertAction; #import <UIKit/UIKit.h>
@class UIAlertController;
namespace qr_scanner { namespace scanner {
// Block type that takes a UIAlertAction. Blocks of this type will be called // Block type that takes a UIAlertAction. Blocks of this type will be called
// when the Cancel button of a UIAlertView is pressed. // when the Cancel button of a UIAlertView is pressed.
...@@ -22,6 +21,6 @@ typedef void (^CancelAlertAction)(UIAlertAction* alertAction); ...@@ -22,6 +21,6 @@ typedef void (^CancelAlertAction)(UIAlertAction* alertAction);
UIAlertController* DialogForCameraState(CameraState state, UIAlertController* DialogForCameraState(CameraState state,
CancelAlertAction cancelBlock); CancelAlertAction cancelBlock);
} // namespace qr_scanner } // namespace scanner
#endif // IOS_CHROME_BROWSER_UI_QR_SCANNER_QR_SCANNER_ALERTS_H_ #endif // IOS_CHROME_BROWSER_UI_SCANNER_SCANNER_ALERTS_H_
...@@ -2,9 +2,7 @@ ...@@ -2,9 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#import "ios/chrome/browser/ui/qr_scanner/qr_scanner_alerts.h" #import "ios/chrome/browser/ui/scanner/scanner_alerts.h"
#import <UIKit/UIKit.h>
#include "base/logging.h" #include "base/logging.h"
#include "components/version_info/version_info.h" #include "components/version_info/version_info.h"
...@@ -20,9 +18,9 @@ ...@@ -20,9 +18,9 @@
namespace { namespace {
// Returns a "Cancel" UIAlertAction for the given |block|. // Returns a "Cancel" UIAlertAction for the given |block|.
UIAlertAction* CancelAction(qr_scanner::CancelAlertAction block) { UIAlertAction* CancelAction(scanner::CancelAlertAction block) {
NSString* cancelButtonTitle = NSString* cancelButtonTitle =
l10n_util::GetNSString(IDS_IOS_QR_SCANNER_ALERT_CANCEL); l10n_util::GetNSString(IDS_IOS_SCANNER_ALERT_CANCEL);
return [UIAlertAction actionWithTitle:cancelButtonTitle return [UIAlertAction actionWithTitle:cancelButtonTitle
style:UIAlertActionStyleCancel style:UIAlertActionStyleCancel
handler:block]; handler:block];
...@@ -34,7 +32,7 @@ UIAlertAction* CancelAction(qr_scanner::CancelAlertAction block) { ...@@ -34,7 +32,7 @@ UIAlertAction* CancelAction(qr_scanner::CancelAlertAction block) {
UIAlertController* AlertWithCancelButton( UIAlertController* AlertWithCancelButton(
NSString* title, NSString* title,
NSString* body, NSString* body,
qr_scanner::CancelAlertAction cancelBlock) { scanner::CancelAlertAction cancelBlock) {
UIAlertController* dialog = UIAlertController* dialog =
[UIAlertController alertControllerWithTitle:title [UIAlertController alertControllerWithTitle:title
message:body message:body
...@@ -54,25 +52,25 @@ UIAlertController* AlertWithCancelButton( ...@@ -54,25 +52,25 @@ UIAlertController* AlertWithCancelButton(
// Returns a UIAlertController to be displayed when the camera state is // Returns a UIAlertController to be displayed when the camera state is
// CAMERA_PERMISSION_DENIED. // CAMERA_PERMISSION_DENIED.
UIAlertController* CameraPermissionDeniedDialog( UIAlertController* CameraPermissionDeniedDialog(
qr_scanner::CancelAlertAction cancelBlock) { scanner::CancelAlertAction cancelBlock) {
NSURL* settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; NSURL* settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
if (![[UIApplication sharedApplication] canOpenURL:settingsURL]) { if (![[UIApplication sharedApplication] canOpenURL:settingsURL]) {
// Display a dialog instructing the user how to change the settings. // Display a dialog instructing the user how to change the settings.
NSString* dialogTitle = l10n_util::GetNSString( NSString* dialogTitle =
IDS_IOS_QR_SCANNER_CAMERA_PERMISSIONS_HELP_TITLE); l10n_util::GetNSString(IDS_IOS_SCANNER_CAMERA_PERMISSIONS_HELP_TITLE);
NSString* dialogBody = l10n_util::GetNSString( NSString* dialogBody =
IDS_IOS_QR_SCANNER_CAMERA_PERMISSIONS_HELP_DETAIL); l10n_util::GetNSString(IDS_IOS_SCANNER_CAMERA_PERMISSIONS_HELP_DETAIL);
return AlertWithCancelButton(dialogTitle, dialogBody, cancelBlock); return AlertWithCancelButton(dialogTitle, dialogBody, cancelBlock);
} }
// Display a dialog with a link to the Settings app. // Display a dialog with a link to the Settings app.
NSString* dialogTitle = l10n_util::GetNSString( NSString* dialogTitle = l10n_util::GetNSString(
IDS_IOS_QR_SCANNER_CAMERA_PERMISSIONS_HELP_TITLE_GO_TO_SETTINGS); IDS_IOS_SCANNER_CAMERA_PERMISSIONS_HELP_TITLE_GO_TO_SETTINGS);
NSString* dialogBody = l10n_util::GetNSString( NSString* dialogBody = l10n_util::GetNSString(
IDS_IOS_QR_SCANNER_CAMERA_PERMISSIONS_HELP_DETAIL_GO_TO_SETTINGS); IDS_IOS_SCANNER_CAMERA_PERMISSIONS_HELP_DETAIL_GO_TO_SETTINGS);
NSString* settingsButton = l10n_util::GetNSString( NSString* settingsButton = l10n_util::GetNSString(
IDS_IOS_QR_SCANNER_CAMERA_PERMISSIONS_HELP_GO_TO_SETTINGS); IDS_IOS_SCANNER_CAMERA_PERMISSIONS_HELP_GO_TO_SETTINGS);
UIAlertController* dialog = UIAlertController* dialog =
AlertWithCancelButton(dialogTitle, dialogBody, cancelBlock); AlertWithCancelButton(dialogTitle, dialogBody, cancelBlock);
...@@ -94,44 +92,44 @@ UIAlertController* CameraPermissionDeniedDialog( ...@@ -94,44 +92,44 @@ UIAlertController* CameraPermissionDeniedDialog(
} // namespace } // namespace
namespace qr_scanner { namespace scanner {
UIAlertController* DialogForCameraState( UIAlertController* DialogForCameraState(
CameraState state, CameraState state,
qr_scanner::CancelAlertAction cancelBlock) { scanner::CancelAlertAction cancelBlock) {
NSString* dialogTitle = nil; NSString* dialogTitle = nil;
NSString* dialogBody = nil; NSString* dialogBody = nil;
switch (state) { switch (state) {
case qr_scanner::CAMERA_AVAILABLE: case scanner::CAMERA_AVAILABLE:
case qr_scanner::CAMERA_NOT_LOADED: case scanner::CAMERA_NOT_LOADED:
NOTREACHED(); NOTREACHED();
return nil; return nil;
case qr_scanner::CAMERA_IN_USE_BY_ANOTHER_APPLICATION: case scanner::CAMERA_IN_USE_BY_ANOTHER_APPLICATION:
dialogTitle = dialogTitle =
l10n_util::GetNSString(IDS_IOS_QR_SCANNER_CAMERA_IN_USE_ALERT_TITLE); l10n_util::GetNSString(IDS_IOS_SCANNER_CAMERA_IN_USE_ALERT_TITLE);
dialogBody = dialogBody =
l10n_util::GetNSString(IDS_IOS_QR_SCANNER_CAMERA_IN_USE_ALERT_DETAIL); l10n_util::GetNSString(IDS_IOS_SCANNER_CAMERA_IN_USE_ALERT_DETAIL);
return AlertWithCancelButton(dialogTitle, dialogBody, cancelBlock); return AlertWithCancelButton(dialogTitle, dialogBody, cancelBlock);
case qr_scanner::MULTIPLE_FOREGROUND_APPS: case scanner::MULTIPLE_FOREGROUND_APPS:
dialogTitle = l10n_util::GetNSString( dialogTitle = l10n_util::GetNSString(
IDS_IOS_QR_SCANNER_MULTIPLE_FOREGROUND_APPS_ALERT_TITLE); IDS_IOS_SCANNER_MULTIPLE_FOREGROUND_APPS_ALERT_TITLE);
dialogBody = l10n_util::GetNSString( dialogBody = l10n_util::GetNSString(
IDS_IOS_QR_SCANNER_MULTIPLE_FOREGROUND_APPS_ALERT_DETAIL); IDS_IOS_SCANNER_MULTIPLE_FOREGROUND_APPS_ALERT_DETAIL);
return AlertWithCancelButton(dialogTitle, dialogBody, cancelBlock); return AlertWithCancelButton(dialogTitle, dialogBody, cancelBlock);
case qr_scanner::CAMERA_PERMISSION_DENIED: case scanner::CAMERA_PERMISSION_DENIED:
return CameraPermissionDeniedDialog(cancelBlock); return CameraPermissionDeniedDialog(cancelBlock);
case qr_scanner::CAMERA_UNAVAILABLE_DUE_TO_SYSTEM_PRESSURE: case scanner::CAMERA_UNAVAILABLE_DUE_TO_SYSTEM_PRESSURE:
case qr_scanner::CAMERA_UNAVAILABLE: case scanner::CAMERA_UNAVAILABLE:
dialogTitle = l10n_util::GetNSString( dialogTitle = l10n_util::GetNSString(
IDS_IOS_QR_SCANNER_CAMERA_UNAVAILABLE_ALERT_TITLE); IDS_IOS_SCANNER_CAMERA_UNAVAILABLE_ALERT_TITLE);
dialogBody = l10n_util::GetNSString( dialogBody = l10n_util::GetNSString(
IDS_IOS_QR_SCANNER_CAMERA_UNAVAILABLE_ALERT_DETAIL); IDS_IOS_SCANNER_CAMERA_UNAVAILABLE_ALERT_DETAIL);
return AlertWithCancelButton(dialogTitle, dialogBody, cancelBlock); return AlertWithCancelButton(dialogTitle, dialogBody, cancelBlock);
} }
} }
} // namespace qr_scanner } // namespace scanner
// Copyright 2017 The Chromium Authors. All rights reserved. // Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_QR_SCANNER_QR_SCANNER_PRESENTING_H_ #ifndef IOS_CHROME_BROWSER_UI_SCANNER_SCANNER_PRESENTING_H_
#define IOS_CHROME_BROWSER_UI_QR_SCANNER_QR_SCANNER_PRESENTING_H_ #define IOS_CHROME_BROWSER_UI_SCANNER_SCANNER_PRESENTING_H_
// QRScannerPresenting contains methods that control how the QR scanner UI is // ScannerPresenting contains methods that control how a scanner UI is
// dismissed on screen. // dismissed on screen.
@protocol QRScannerPresenting @protocol ScannerPresenting
// Asks the implementer to dismiss the given |controller| and call the given // Asks the implementer to dismiss the given |controller| and call the given
// |completion| afterwards. // |completion| afterwards.
- (void)dismissQRScannerViewController:(UIViewController*)controller - (void)dismissScannerViewController:(UIViewController*)controller
completion:(void (^)(void))completion; completion:(void (^)(void))completion;
@end @end
#endif // IOS_CHROME_BROWSER_UI_QR_SCANNER_QR_SCANNER_PRESENTING_H_ #endif // IOS_CHROME_BROWSER_UI_SCANNER_SCANNER_PRESENTING_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_SCANNER_SCANNER_TRANSITIONING_DELEGATE_H_
#define IOS_CHROME_BROWSER_UI_SCANNER_SCANNER_TRANSITIONING_DELEGATE_H_
#import <UIKit/UIKit.h>
@interface ScannerTransitioningDelegate
: NSObject <UIViewControllerTransitioningDelegate>
@end
#endif // IOS_CHROME_BROWSER_UI_SCANNER_SCANNER_TRANSITIONING_DELEGATE_H_
// Copyright 2016 The Chromium Authors. All rights reserved. // Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#import "ios/chrome/browser/ui/qr_scanner/qr_scanner_transitioning_delegate.h" #import "ios/chrome/browser/ui/scanner/scanner_transitioning_delegate.h"
#include "base/ios/block_types.h" #include "base/ios/block_types.h"
...@@ -15,28 +15,28 @@ namespace { ...@@ -15,28 +15,28 @@ namespace {
// The default animation duration. // The default animation duration.
const NSTimeInterval kDefaultDuration = 0.25; const NSTimeInterval kDefaultDuration = 0.25;
enum QRScannerTransition { PRESENT, DISMISS }; enum ScannerTransition { PRESENT, DISMISS };
} // namespace } // namespace
// Animates the QR Scanner transition. If initialized with the |PRESENT| // Animates the Scanner transition. If initialized with the |PRESENT|
// transition, positions the QR Scanner view below its presenting view // transition, positions the Scanner view below its presenting view
// controller's view in the container view and animates the presenting view to // controller's view in the container view and animates the presenting view to
// slide up. If initialized with the |DISMISS| transition, positions the // slide up. If initialized with the |DISMISS| transition, positions the
// presenting view controller's view above the QR Scanner view in the container // presenting view controller's view above the Scanner view in the container
// view and animates the presenting view to slide down. // view and animates the presenting view to slide down.
@interface QRScannerTransitionAnimator @interface ScannerTransitionAnimator
: NSObject<UIViewControllerAnimatedTransitioning> { : NSObject <UIViewControllerAnimatedTransitioning> {
QRScannerTransition _transition; ScannerTransition _transition;
} }
- (instancetype)initWithTransition:(QRScannerTransition)transition; - (instancetype)initWithTransition:(ScannerTransition)transition;
@end @end
@implementation QRScannerTransitionAnimator @implementation ScannerTransitionAnimator
- (instancetype)initWithTransition:(QRScannerTransition)transition { - (instancetype)initWithTransition:(ScannerTransition)transition {
self = [super init]; self = [super init];
if (self) { if (self) {
_transition = transition; _transition = transition;
...@@ -108,18 +108,18 @@ enum QRScannerTransition { PRESENT, DISMISS }; ...@@ -108,18 +108,18 @@ enum QRScannerTransition { PRESENT, DISMISS };
@end @end
@implementation QRScannerTransitioningDelegate @implementation ScannerTransitioningDelegate
- (id<UIViewControllerAnimatedTransitioning>) - (id<UIViewControllerAnimatedTransitioning>)
animationControllerForPresentedController:(UIViewController*)presented animationControllerForPresentedController:(UIViewController*)presented
presentingController:(UIViewController*)presenting presentingController:(UIViewController*)presenting
sourceController:(UIViewController*)source { sourceController:(UIViewController*)source {
return [[QRScannerTransitionAnimator alloc] initWithTransition:PRESENT]; return [[ScannerTransitionAnimator alloc] initWithTransition:PRESENT];
} }
- (id<UIViewControllerAnimatedTransitioning>) - (id<UIViewControllerAnimatedTransitioning>)
animationControllerForDismissedController:(UIViewController*)dismissed { animationControllerForDismissedController:(UIViewController*)dismissed {
return [[QRScannerTransitionAnimator alloc] initWithTransition:DISMISS]; return [[ScannerTransitionAnimator alloc] initWithTransition:DISMISS];
} }
@end @end
...@@ -174,7 +174,7 @@ const CGFloat kFlashDuration = 0.5; ...@@ -174,7 +174,7 @@ const CGFloat kFlashDuration = 0.5;
} }
- (NSString*)caption { - (NSString*)caption {
return nil; return @"";
} }
#pragma mark - private methods #pragma mark - private methods
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_SCANNER_SCANNER_VIEW_CONTROLLER_H_
#define IOS_CHROME_BROWSER_UI_SCANNER_SCANNER_VIEW_CONTROLLER_H_
#import <UIKit/UIKit.h>
#include "ios/chrome/browser/ui/scanner/camera_controller.h"
#include "ios/chrome/browser/ui/scanner/scanner_view.h"
namespace scannerViewController {
// The reason why the ScannerViewController was dismissed. Used for collecting
// metrics.
enum DismissalReason {
CLOSE_BUTTON,
ERROR_DIALOG,
SCANNED_CODE,
// Not reported. Should be kept last of enum.
IMPOSSIBLY_UNLIKELY_AUTHORIZATION_CHANGE
};
} // namespace scannerViewController
@protocol ScannerPresenting;
// View controller for a generic scanner. This is an abstract class that creates
// the view and camera controller, required for a QR code or Credit Card
// Scanner.
@interface ScannerViewController
: UIViewController <CameraControllerDelegate, ScannerViewDelegate>
// Stores the camera controller for the scanner.
@property(nonatomic, readwrite, strong) CameraController* cameraController;
// Stores the presentation provider.
@property(nonatomic, readwrite, weak) id<ScannerPresenting>
presentationProvider;
- (instancetype)initWithPresentationProvider:
(id<ScannerPresenting>)presentationProvider
cameraController:(CameraController*)cameraController
NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithNibName:(NSString*)name
bundle:(NSBundle*)bundle NS_UNAVAILABLE;
- (instancetype)initWithCoder:(NSCoder*)coder NS_UNAVAILABLE;
// Returns a view controller to be presented based on the camera state. Returns
// |self| if the camera is available or an appropriate UIAlertController if
// there was an error loading the camera.
- (UIViewController*)getViewControllerToPresent;
// Builds the scanner view. Must be overridden in the subclass.
- (ScannerView*)buildScannerView;
// Dismiss scanner. Subclass can override to update metrics.
// implementation.
- (void)dismissForReason:(scannerViewController::DismissalReason)reason
withCompletion:(void (^)(void))completion;
- (void)stopReceivingNotifications;
- (void)setTorchMode:(AVCaptureTorchMode)mode;
@end
#endif // IOS_CHROME_BROWSER_UI_SCANNER_SCANNER_VIEW_CONTROLLER_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/scanner/scanner_view_controller.h"
#import <AVFoundation/AVFoundation.h>
#include "base/logging.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "ios/chrome/browser/ui/commands/load_query_commands.h"
#include "ios/chrome/browser/ui/scanner/scanner_alerts.h"
#include "ios/chrome/browser/ui/scanner/scanner_presenting.h"
#include "ios/chrome/browser/ui/scanner/scanner_transitioning_delegate.h"
#include "ios/chrome/browser/ui/scanner/scanner_view.h"
#include "ios/chrome/grit/ios_strings.h"
#include "ui/base/l10n/l10n_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
using base::UserMetricsAction;
@interface ScannerViewController () {
// The scanned result.
NSString* _result;
// Whether the scanned result should be immediately loaded.
BOOL _loadResultImmediately;
// The transitioning delegate used for presenting and dismissing the scanner.
ScannerTransitioningDelegate* _transitioningDelegate;
}
@property(nonatomic, readwrite, weak) id<LoadQueryCommands> queryLoader;
// Stores the view for the scanner. Can be subclassed as a QR code or Credit
// Card scanner view.
@property(nonatomic, readwrite) ScannerView* scannerView;
@end
@implementation ScannerViewController
#pragma mark - lifecycle
- (instancetype)
initWithPresentationProvider:(id<ScannerPresenting>)presentationProvider
cameraController:(CameraController*)cameraController {
self = [super initWithNibName:nil bundle:nil];
if (self) {
_presentationProvider = presentationProvider;
_cameraController = cameraController;
}
return self;
}
#pragma mark - UIAccessibilityAction
- (BOOL)accessibilityPerformEscape {
[self dismissForReason:scannerViewController::CLOSE_BUTTON
withCompletion:nil];
return YES;
}
#pragma mark - UIViewController
- (void)viewDidLoad {
[super viewDidLoad];
DCHECK(_cameraController);
[self.view addSubview:self.scannerView];
// Constraints for |self.scannerView|.
[self.scannerView setTranslatesAutoresizingMaskIntoConstraints:NO];
[NSLayoutConstraint activateConstraints:@[
[[self.scannerView leadingAnchor]
constraintEqualToAnchor:[self.view leadingAnchor]],
[[self.scannerView trailingAnchor]
constraintEqualToAnchor:[self.view trailingAnchor]],
[[self.scannerView topAnchor]
constraintEqualToAnchor:[self.view topAnchor]],
[[self.scannerView bottomAnchor]
constraintEqualToAnchor:[self.view bottomAnchor]],
]];
AVCaptureVideoPreviewLayer* previewLayer = [self.scannerView getPreviewLayer];
switch ([_cameraController getAuthorizationStatus]) {
case AVAuthorizationStatusNotDetermined:
[_cameraController
requestAuthorizationAndLoadCaptureSession:previewLayer];
break;
case AVAuthorizationStatusAuthorized:
[_cameraController loadCaptureSession:previewLayer];
break;
case AVAuthorizationStatusRestricted:
case AVAuthorizationStatusDenied:
// If this happens, then the user is really unlucky:
// The authorization status changed in between the moment this VC was
// instantiated and presented, and the moment viewDidLoad was called.
[self dismissForReason:scannerViewController::
IMPOSSIBLY_UNLIKELY_AUTHORIZATION_CHANGE
withCompletion:nil];
break;
}
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self startReceivingNotifications];
[_cameraController startRecording];
// Reset torch.
[self setTorchMode:AVCaptureTorchModeOff];
}
- (void)viewWillTransitionToSize:(CGSize)size
withTransitionCoordinator:
(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
CGFloat epsilon = 0.0001;
// Note: targetTransform is always either identity or a 90, -90, or 180 degree
// rotation.
CGAffineTransform targetTransform = coordinator.targetTransform;
CGFloat angle = atan2f(targetTransform.b, targetTransform.a);
if (fabs(angle) > epsilon) {
// Rotate the preview in the opposite direction of the interface rotation
// and add a small value to the angle to force the rotation to occur in the
// correct direction when rotating by 180 degrees.
void (^animationBlock)(id<UIViewControllerTransitionCoordinatorContext>) =
^void(id<UIViewControllerTransitionCoordinatorContext> context) {
[self.scannerView rotatePreviewByAngle:(epsilon - angle)];
};
// Note: The completion block is called even if the animation is
// interrupted, for example by pressing the home button, with the same
// target transform as the animation block.
void (^completionBlock)(id<UIViewControllerTransitionCoordinatorContext>) =
^void(id<UIViewControllerTransitionCoordinatorContext> context) {
[self.scannerView finishPreviewRotation];
};
[coordinator animateAlongsideTransition:animationBlock
completion:completionBlock];
} else if (!CGSizeEqualToSize(self.view.frame.size, size)) {
// Reset the size of the preview if the bounds of the view controller
// changed. This can happen if entering or leaving Split View mode on iPad.
[self.scannerView resetPreviewFrame:size];
[_cameraController
resetVideoOrientation:[self.scannerView getPreviewLayer]];
}
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[_cameraController stopRecording];
[self stopReceivingNotifications];
// Reset torch.
[self setTorchMode:AVCaptureTorchModeOff];
}
- (BOOL)prefersStatusBarHidden {
return YES;
}
#pragma mark - public methods
- (UIViewController*)getViewControllerToPresent {
DCHECK(_cameraController);
switch ([_cameraController getAuthorizationStatus]) {
case AVAuthorizationStatusNotDetermined:
case AVAuthorizationStatusAuthorized:
_transitioningDelegate = [[ScannerTransitioningDelegate alloc] init];
[self setTransitioningDelegate:_transitioningDelegate];
return self;
case AVAuthorizationStatusRestricted:
case AVAuthorizationStatusDenied:
return scanner::DialogForCameraState(scanner::CAMERA_PERMISSION_DENIED,
nil);
}
}
- (void)dismissForReason:(scannerViewController::DismissalReason)reason
withCompletion:(void (^)(void))completion {
[self.presentationProvider dismissScannerViewController:self
completion:completion];
}
- (ScannerView*)buildScannerView {
NOTIMPLEMENTED();
return nil;
}
#pragma mark - private methods
// Starts receiving notifications about the UIApplication going to background.
- (void)startReceivingNotifications {
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleUIApplicationWillResignActiveNotification)
name:UIApplicationWillResignActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector
(handleUIAccessibilityAnnouncementDidFinishNotification:)
name:UIAccessibilityAnnouncementDidFinishNotification
object:nil];
}
// Stops receiving all notifications.
- (void)stopReceivingNotifications {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
// Requests the torch mode to be set to |mode| by the |_cameraController|
// and the icon of the torch button to be changed by the |self.scannerView|.
- (void)setTorchMode:(AVCaptureTorchMode)mode {
[_cameraController setTorchMode:mode];
}
- (ScannerView*)scannerView {
if (!_scannerView) {
_scannerView = [self buildScannerView];
}
return _scannerView;
}
#pragma mark - notification handlers
- (void)handleUIApplicationWillResignActiveNotification {
[self setTorchMode:AVCaptureTorchModeOff];
}
- (void)handleUIAccessibilityAnnouncementDidFinishNotification:
(NSNotification*)notification {
NSString* announcement = [[notification userInfo]
valueForKey:UIAccessibilityAnnouncementKeyStringValue];
if ([announcement
isEqualToString:
l10n_util::GetNSString(
IDS_IOS_SCANNER_SCANNED_ACCESSIBILITY_ANNOUNCEMENT)]) {
DCHECK(_result);
[self dismissForReason:scannerViewController::SCANNED_CODE
withCompletion:^{
[self.queryLoader loadQuery:_result
immediately:_loadResultImmediately];
}];
}
}
#pragma mark - CameraControllerDelegate
- (void)captureSessionIsConnected {
[_cameraController setViewport:[self.scannerView viewportRectOfInterest]];
}
- (void)cameraStateChanged:(scanner::CameraState)state {
switch (state) {
case scanner::CAMERA_AVAILABLE:
// Dismiss any presented alerts.
if ([self presentedViewController]) {
[self dismissViewControllerAnimated:YES completion:nil];
}
break;
case scanner::CAMERA_IN_USE_BY_ANOTHER_APPLICATION:
case scanner::MULTIPLE_FOREGROUND_APPS:
case scanner::CAMERA_PERMISSION_DENIED:
case scanner::CAMERA_UNAVAILABLE_DUE_TO_SYSTEM_PRESSURE:
case scanner::CAMERA_UNAVAILABLE: {
// Dismiss any presented alerts.
if ([self presentedViewController]) {
[self dismissViewControllerAnimated:YES completion:nil];
}
[self presentViewController:
scanner::DialogForCameraState(
state,
^(UIAlertAction*) {
[self dismissForReason:scannerViewController::ERROR_DIALOG
withCompletion:nil];
})
animated:YES
completion:nil];
break;
}
case scanner::CAMERA_NOT_LOADED:
NOTREACHED();
break;
}
}
- (void)torchStateChanged:(BOOL)torchIsOn {
[self.scannerView setTorchButtonTo:torchIsOn];
}
- (void)torchAvailabilityChanged:(BOOL)torchIsAvailable {
[self.scannerView enableTorchButton:torchIsAvailable];
}
- (void)receiveQRScannerResult:(NSString*)result loadImmediately:(BOOL)load {
if (UIAccessibilityIsVoiceOverRunning()) {
// Post a notification announcing that a code was scanned. QR scanner will
// be dismissed when the UIAccessibilityAnnouncementDidFinishNotification is
// received.
_result = [result copy];
_loadResultImmediately = load;
UIAccessibilityPostNotification(
UIAccessibilityAnnouncementNotification,
l10n_util::GetNSString(
IDS_IOS_SCANNER_SCANNED_ACCESSIBILITY_ANNOUNCEMENT));
} else {
[self.scannerView animateScanningResultWithCompletion:^void(void) {
[self dismissForReason:scannerViewController::SCANNED_CODE
withCompletion:^{
[self.queryLoader loadQuery:result immediately:load];
}];
}];
}
}
#pragma mark - ScannerViewDelegate
- (void)dismissScannerView:(id)sender {
[self dismissForReason:scannerViewController::CLOSE_BUTTON
withCompletion:nil];
}
- (void)toggleTorch:(id)sender {
if ([_cameraController isTorchActive]) {
[self setTorchMode:AVCaptureTorchModeOff];
} else {
base::RecordAction(UserMetricsAction("MobileQRScannerTorchOn"));
[self setTorchMode:AVCaptureTorchModeOn];
}
}
@end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment