The QR Scanner provides a way of scanning QR codes and bar codes directly from Chrome. It is developed behind the
EnableQRCodeReader experimental flag.
QRScannerViewControllerwith this delegate.
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
QRScannerViewand is responsible for displaying alerts from
AVCaptureSessionfor the camera. It is responsible for loading the camera, listening for camera notifications, receiving the scanned result and informing the
QRScannerViewControllerabout 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
QRScannerViewController owns an instance of
QRScannerView and is their delegate.
viewControllerToPresentmethod checks if camera permission is granted by calling
viewControllerToPresent. If the user has not previously granted camera permission to the application, the
QRScannerViewControllerinstance 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.
QRScannerViewControllerwill be returned as the view controller to present, and the
CameraControllerwill start loading the camera on a separate dispatch queue.
Camera initialization is handled by the
loadCaptureSession method of the
CAMERA_UNAVAILABLEand an error dialog is displayed if:
CAMERA_AVAILABLE, which is reported asynchronously to
CameraControllerstarts listening for camera notifications.
AVCaptureVideoPreviewLayer is created by the
QRScannerViewis initialized by the
loadVideoPreviewLayer:with the loaded preview. If the camera is already loaded,
CameraControllerattaches the preview to the
AVCaptureSession. Otherwise the preview is attached immediately after the
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.
QRScannerViewControllersets the viewport on
viewDidAppear, to make sure that the preview layer is of the correct size and position when the viewport is calculated.
cameraIsReadymethod of its delegate to notify the
QRScannerViewControllerthat 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
AVCaptureSessionWasInterruptedNotification, handled by setting the camera state to one of:
MULTIPLE_FOREGROUND_APPS, based on the value of
AVCaptureSessionInterruptionReasonKeyin the notification's user info.
AVCaptureSessionInterruptionEndedNotification, handled by setting the camera state to
AVCaptureDeviceWasDisconnected, handled by setting the camera state to
The current state of the torch is obtained using key-value observing of the
torchActiveproperty, and the delegate is informed using
torchAvailable. Torch is only considered available if both properties are
YESand the delegate is informed using
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.
CameraControllerchecks the type of the scanned code, and if the code can only contain numbers, sets the
CameraControllerstops the capture session.
Supported codes (from Machine Readable Object Types):
The QR scanner consists of three views:
PreviewOverlayViewand 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.
VideoPreviewViewdoes 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.
PreviewOverlayViewis 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.Actionwhen the user opens the QR scanner from searching for it in Spotlight.
ApplicationShortcut.ScanQRCodePressedwhen the user opens the QR scanner from 3D Touch application shortcuts.
MobileQRScannerClosewhen the user closes the QR scanner without scanning a code.
MobileQRScannerErrorwhen the user closes the QR scanner from an error dialog.
MobileQRScannerScannedCodewhen the user scans a code.
MobileQRScannerTorchOnwhen 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.