Commit f5e3835b authored by Ehsan Kia's avatar Ehsan Kia Committed by Commit Bot

[QRCode] Display error message when a camera failure happens.

Screenshot:
https://screenshot.googleplex.com/7ZyeNAwxjxC.png

Bug: 1052026
Change-Id: Ie0e5f58b03e1fdc21d2c6dafc1c6990636b2ebc4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2054564
Commit-Queue: Ehsan Kia <ehsankia@google.com>
Reviewed-by: default avatarGayane Petrosyan <gayane@chromium.org>
Cr-Commit-Position: refs/heads/master@{#741222}
parent 0e55e776
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2020 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. -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/permission_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/qrcode_camera_error_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="8dp"
android:drawableStart="@drawable/ic_error"
android:gravity="center_vertical"
android:maxWidth="250dp"
android:textAppearance="@style/TextAppearance.ErrorCaption" />
</LinearLayout>
...@@ -20,7 +20,8 @@ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback ...@@ -20,7 +20,8 @@ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
private static final String THREAD_NAME = "CameraHandlerThread"; private static final String THREAD_NAME = "CameraHandlerThread";
private final Context mContext; private final Context mContext;
private final Camera.PreviewCallback mCameraCallback; private final Camera.PreviewCallback mPreviewCallback;
private final Camera.ErrorCallback mErrorCallback;
private int mCameraId; private int mCameraId;
private Camera mCamera; private Camera mCamera;
...@@ -29,12 +30,15 @@ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback ...@@ -29,12 +30,15 @@ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
/** /**
* The CameraPreview constructor. * The CameraPreview constructor.
* @param context The context to use for user permissions. * @param context The context to use for user permissions.
* @param cameraCallback The callback to processing camera preview. * @param previewCallback The callback to processing camera preview.
* @param errorCallback The callback when an error happens using the camera.
*/ */
public CameraPreview(Context context, Camera.PreviewCallback cameraCallback) { public CameraPreview(Context context, Camera.PreviewCallback previewCallback,
Camera.ErrorCallback errorCallback) {
super(context); super(context);
mContext = context; mContext = context;
mCameraCallback = cameraCallback; mPreviewCallback = previewCallback;
mErrorCallback = errorCallback;
} }
/** Obtains a camera and starts the preview. */ /** Obtains a camera and starts the preview. */
...@@ -89,7 +93,8 @@ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback ...@@ -89,7 +93,8 @@ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
try { try {
mCamera.setPreviewDisplay(getHolder()); mCamera.setPreviewDisplay(getHolder());
mCamera.setDisplayOrientation(getCameraOrientation()); mCamera.setDisplayOrientation(getCameraOrientation());
mCamera.setOneShotPreviewCallback(mCameraCallback); mCamera.setOneShotPreviewCallback(mPreviewCallback);
mCamera.setErrorCallback(mErrorCallback);
Camera.Parameters parameters = mCamera.getParameters(); Camera.Parameters parameters = mCamera.getParameters();
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
...@@ -97,7 +102,7 @@ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback ...@@ -97,7 +102,7 @@ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
mCamera.startPreview(); mCamera.startPreview();
} catch (Exception e) { } catch (Exception e) {
// TODO(gayane): Should show error message to users, when error strings are approved. mErrorCallback.onError(Camera.CAMERA_ERROR_UNKNOWN, mCamera);
} }
} }
...@@ -110,6 +115,7 @@ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback ...@@ -110,6 +115,7 @@ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
} }
mCamera.setOneShotPreviewCallback(null); mCamera.setOneShotPreviewCallback(null);
mCamera.setErrorCallback(null);
try { try {
mCamera.stopPreview(); mCamera.stopPreview();
} catch (RuntimeException e) { } catch (RuntimeException e) {
...@@ -117,7 +123,7 @@ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback ...@@ -117,7 +123,7 @@ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
} }
} }
/** Calculates camera's orientation based on displaye's orientation and camera. */ /** Calculates camera's orientation based on display's orientation and camera. */
private int getCameraOrientation() { private int getCameraOrientation() {
Camera.CameraInfo info = new Camera.CameraInfo(); Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(mCameraId, info); Camera.getCameraInfo(mCameraId, info);
...@@ -168,12 +174,12 @@ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback ...@@ -168,12 +174,12 @@ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
* Returns an instance of the Camera for the give id. Returns null if camera is used or doesn't * Returns an instance of the Camera for the give id. Returns null if camera is used or doesn't
* exist. * exist.
*/ */
private static Camera getCameraInstance(int cameraId) { private Camera getCameraInstance(int cameraId) {
Camera camera = null; Camera camera = null;
try { try {
camera = Camera.open(cameraId); camera = Camera.open(cameraId);
} catch (RuntimeException e) { } catch (RuntimeException e) {
// TODO(gayane): Should show error message to users, when error strings are approved. mErrorCallback.onError(Camera.CAMERA_ERROR_UNKNOWN, null);
} }
return camera; return camera;
} }
......
...@@ -5,12 +5,15 @@ ...@@ -5,12 +5,15 @@
package org.chromium.chrome.browser.share.qrcode.scan_tab; package org.chromium.chrome.browser.share.qrcode.scan_tab;
import android.content.Context; import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.ErrorCallback;
import android.hardware.Camera.PreviewCallback; import android.hardware.Camera.PreviewCallback;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.TextView;
import org.chromium.ui.widget.ButtonCompat; import org.chromium.ui.widget.ButtonCompat;
...@@ -22,13 +25,14 @@ class QrCodeScanView { ...@@ -22,13 +25,14 @@ class QrCodeScanView {
private final Context mContext; private final Context mContext;
private final FrameLayout mView; private final FrameLayout mView;
private final PreviewCallback mCameraCallback; private final PreviewCallback mCameraPreviewCallback;
private boolean mHasCameraPermission; private boolean mHasCameraPermission;
private boolean mCanPromptForPermission; private boolean mCanPromptForPermission;
private boolean mIsOnForeground; private boolean mIsOnForeground;
private CameraPreview mCameraPreview; private CameraPreview mCameraPreview;
private View mPermissionsView; private View mPermissionsView;
private View mCameraErrorView;
/** /**
* The QrCodeScanView constructor. * The QrCodeScanView constructor.
...@@ -39,11 +43,12 @@ class QrCodeScanView { ...@@ -39,11 +43,12 @@ class QrCodeScanView {
public QrCodeScanView(Context context, PreviewCallback cameraCallback, public QrCodeScanView(Context context, PreviewCallback cameraCallback,
PermissionPrompter permissionPrompter) { PermissionPrompter permissionPrompter) {
mContext = context; mContext = context;
mCameraCallback = cameraCallback; mCameraPreviewCallback = cameraCallback;
mView = new FrameLayout(context); mView = new FrameLayout(context);
mView.setLayoutParams( mView.setLayoutParams(
new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
mPermissionsView = createPermissionView(context, permissionPrompter); mPermissionsView = createPermissionView(context, permissionPrompter);
mCameraErrorView = createCameraErrorView(context);
} }
public View getView() { public View getView() {
...@@ -66,6 +71,26 @@ class QrCodeScanView { ...@@ -66,6 +71,26 @@ class QrCodeScanView {
return permissionView; return permissionView;
} }
private View createCameraErrorView(Context context) {
return (View) LayoutInflater.from(context).inflate(
org.chromium.chrome.browser.share.qrcode.R.layout.qrcode_camera_error_layout, null,
false);
}
private final ErrorCallback mCameraErrorCallback = new ErrorCallback() {
@Override
public void onError(int error, Camera camera) {
if (mCameraPreview != null) {
mCameraPreview.stopCamera();
mCameraPreview = null;
}
// TODO(ehsankia): Adjust error message given error code.
String errorString = mContext.getResources().getString(
org.chromium.chrome.R.string.qr_code_in_use_camera_error);
displayCameraErrorDialog(errorString);
}
};
/** /**
* Sets camera if possible. * Sets camera if possible.
* *
...@@ -121,7 +146,8 @@ class QrCodeScanView { ...@@ -121,7 +146,8 @@ class QrCodeScanView {
} }
if (mHasCameraPermission) { if (mHasCameraPermission) {
mCameraPreview = new CameraPreview(mContext, mCameraCallback); mCameraPreview =
new CameraPreview(mContext, mCameraPreviewCallback, mCameraErrorCallback);
mView.addView(mCameraPreview); mView.addView(mCameraPreview);
mView.addView(new CameraPreviewOverlay(mContext)); mView.addView(new CameraPreviewOverlay(mContext));
...@@ -150,4 +176,14 @@ class QrCodeScanView { ...@@ -150,4 +176,14 @@ class QrCodeScanView {
mView.removeAllViews(); mView.removeAllViews();
mView.addView(mPermissionsView); mView.addView(mPermissionsView);
} }
/** Displays the camera error dialog. */
private void displayCameraErrorDialog(String errorString) {
TextView cameraErrorTextView = (TextView) mCameraErrorView.findViewById(
org.chromium.chrome.browser.share.qrcode.R.id.qrcode_camera_error_text);
cameraErrorTextView.setText(errorString);
mView.removeAllViews();
mView.addView(mCameraErrorView);
}
} }
...@@ -4006,6 +4006,22 @@ The site does NOT gain access to the camera. The camera images are only visible ...@@ -4006,6 +4006,22 @@ The site does NOT gain access to the camera. The camera images are only visible
Continue Continue
</message> </message>
<message name="IDS_QR_CODE_NO_CAMERA_ERROR" desc="Error text shown when no camera is found.">
To scan a QR code, use a device with a camera.
</message>
<message name="IDS_QR_CODE_DISABLED_CAMERA_ERROR" desc="Error text shown when the camera is disabled by the device policy manager.">
The organization that manages your device has turned off your camera.
</message>
<message name="IDS_QR_CODE_IN_USE_CAMERA_ERROR" desc="Error text shown when the camera is in use by other apps.">
Can't open your camera. Restart your device and try again.
</message>
<message name="IDS_QR_CODE_HARDWARE_CAMERA_ERROR" desc="Error text shown when the camera cannot start due to a hardware error.">
Can't open your camera. Something went wrong.
</message>
<!-- Chime DFM module strings --> <!-- Chime DFM module strings -->
<message name="IDS_CHIME_MODULE_TITLE" desc="Text shown when the chime module is referenced in install start, success, failure UI (e.g. in IDS_MODULE_INSTALL_START_TEXT, which will expand to 'Installing Google Notifications Platform for Chrome…')."> <message name="IDS_CHIME_MODULE_TITLE" desc="Text shown when the chime module is referenced in install start, success, failure UI (e.g. in IDS_MODULE_INSTALL_START_TEXT, which will expand to 'Installing Google Notifications Platform for Chrome…').">
Google Notifications Platform Google Notifications Platform
......
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