ios/chrome/browser/qr_scanner/README.md
The QR Scanner provides a way of scanning QR codes and bar codes directly from
Chrome. It is developed behind the EnableQRCodeReader experimental flag.
[TOC]
QRScannerViewControllerDelegate
protocol.QRScannerViewController with this delegate.viewControllerToPresent.The QR Scanner is presented as a full-screen view controller displaying a video preview, a control for the camera's torch, and a control for closing the QR scanner.
The QR Scanner is presented using a custom transition animation which makes it appear to be originally positioned under the presenting view controller.
The QR scanner can be accessed from the 3D Touch application shortcuts on
supported devices. The SpotlightActions experiment allows the QR scanner to be
accessed from Spotlight search. More info about Spotlight actions can be found
at go/chrome-ios-spotlight and crbug.com/608733. Planned and rejected entry
points are described in the design doc at go/chrome-ios-qr-code.
Tests for QR Scanner are a part of ios_chrome_ui_egtests.
CameraController and the QRScannerView and is responsible for
displaying alerts from QRScannerAlerts.AVCaptureSession for the camera. It is
responsible for loading the camera, listening for camera notifications,
receiving the scanned result and informing the QRScannerViewController
about changes to the state of the camera or the torch.Operations performed by CameraController are done on a separate dispatch
queue, as recommended by the documentation for
AVCaptureSession.
QRScannerViewController owns an instance of CameraController and
QRScannerView and is their delegate.
viewControllerToPresent method checks if camera permission is
granted by calling checkPermissionsAndLoadCamera of the
CameraController.viewControllerToPresent. If the user has not previously granted camera
permission to the application, the QRScannerViewController instance will
be returned, and an error will be displayed by the QR scanner if the user
denies the permission in the system dialog. The error dialog prompts the
user to change this setting and includes a link to the Settings app, if
available.QRScannerViewController will be
returned as the view controller to present, and the CameraController will
start loading the camera on a separate dispatch queue.Camera initialization is handled by the loadCaptureSession method of the
CameraController.
CAMERA_UNAVAILABLE and an error dialog is
displayed if:
AVCaptureSession,AVCaptureSession,CAMERA_AVAILABLE, which is reported asynchronously to
QRScannerViewController, and CameraController starts listening for
camera notifications.viewWillAppear.hasTorch and
isTorchAvailable of the AVCaptureDevice are both YES.AVCaptureTorchModeOn and AVCaptureTorchModeOff.The AVCaptureVideoPreviewLayer is created by the QRScannerView:
QRScannerView is initialized by the QRScannerViewController.viewDidLoad, QRScannerViewController calls loadVideoPreviewLayer:
with the loaded preview. If the camera is already loaded,
CameraController attaches the preview to the AVCaptureSession. Otherwise
the preview is attached immediately after the AVCaptureSession is
initialized.The rectangle of interest for the metadata output of the capture session is
calculated to lie exactly inside the viewport drawn by the QRScannerView.
Resetting the viewport causes the video preview to freeze for a short while,
that is why the viewport is only set when the preview is hidden.
QRScannerViewController sets the viewport on viewDidAppear, to make sure
that the preview layer is of the correct size and position when the viewport
is calculated.CameraController calls the cameraIsReady method of its delegate to
notify the QRScannerViewController that the viewport was successfully set
and the camera preview can be displayed.CameraController is listening for the following notifications:
AVCaptureSessionRuntimeErrorNotification, handled by setting the camera
state to CAMERA_UNAVAILABLE,AVCaptureSessionWasInterruptedNotification, handled by setting the camera
state to one of:
APPLICATION_IN_BACKGROUND,CAMERA_IN_USE_BY_ANOTHER_APPLICATION,MULTIPLE_FOREGROUND_APPS,
based on the value of AVCaptureSessionInterruptionReasonKey in the
notification's user info.AVCaptureSessionInterruptionEndedNotification, handled by setting the
camera state to CAMERA_AVAILABLE.AVCaptureDeviceWasDisconnected, handled by setting the camera state to
CAMERA_UNAVAILABLE.The current state of the torch is obtained using key-value observing of the
AVCaptureDevice object.
torchActive property, and
the delegate is informed using torchStateChanged:.hasTorch and
torchAvailable. Torch is only considered available if both properties are
YES and the delegate is informed using torchAvailabilityChanged:.The delegate sets the value of the torch using setTorchMode: and is informed
of the outcome asynchronously.
CameraController implements the AVCaptureMetadataOutputObjectsDelegate and
receives the scanned result on the main queue.
AVMetadataMachineReadableCodeObject.QRScannerViewController.CameraController checks the type of the scanned code, and if the code can
only contain numbers, sets the loadImmediately argument to YES.CameraController stops the capture
session.Supported codes (from Machine Readable Object Types):
The QR scanner consists of three views:
VideoPreviewView, PreviewOverlayView and
controls as subviews.QRScannerTransitioningDelegate implements a custom transition animation:
the QRScannerViewController appears to be positioned below its presenting view
controller. The presenting view controller slides up for presentation and down
for dismissal.
QRScannerView and PreviewOverlayView rotate normally.
VideoPreviewView does not rotate: on viewWillTransitionToSize: the view
is animated to rotate in the opposite direction. This avoids resetting the
viewport rectangle of interest on every screen rotation, because resetting
it causes the video to pause for a while. The view is not positioned using
AutoLayout.PreviewOverlayView is a square that is sqrt(2)-times bigger than
max(width, height) of the QRScannerView, to avoid redrawing the
viewport. This also makes the viewport rotate in place. The view is
positioned using AutoLayout.The following metrics are collected:
IOS.Spotlight.Action when the user opens the QR scanner from searching for
it in Spotlight.ApplicationShortcut.ScanQRCodePressed when the user opens the QR scanner
from 3D Touch application shortcuts.MobileQRScannerClose when the user closes the QR scanner without scanning
a code.MobileQRScannerError when the user closes the QR scanner from an error
dialog.MobileQRScannerScannedCode when the user scans a code.MobileQRScannerTorchOn when the user switches on the torch.Screen rotation on iPad is not handled the same way as on iPhone, as of iOS 9. The counter-rotation animation is not played at the same time as the screen rotation animation, and the camera preview appears to be rotating. This effect is most visible when rotating the screen by 180 degrees, which results in an apparent double-rotation by 360 degrees.