1 /*
2 * Copyright 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 
17 package com.example.android.system.runtimepermissions.camera;
18 
19 import android.content.Context;
20 import android.hardware.Camera;
21 import android.util.Log;
22 import android.view.Surface;
23 import android.view.SurfaceHolder;
24 import android.view.SurfaceView;
25 
26 import java.io.IOException;
27 
28 /**
29  * Camera preview that displays a {@link Camera}.
30  *
31  * Handles basic lifecycle methods to display and stop the preview.
32  * <p>
33  * Implementation is based directly on the documentation at
34  * http://developer.android.com/guide/topics/media/camera.html
35  */
36 public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
37 
38     private static final String TAG = "CameraPreview";
39     private SurfaceHolder mHolder;
40     private Camera mCamera;
41     private Camera.CameraInfo mCameraInfo;
42     private int mDisplayOrientation;
43 
CameraPreview(Context context, Camera camera, Camera.CameraInfo cameraInfo, int displayOrientation)44     public CameraPreview(Context context, Camera camera, Camera.CameraInfo cameraInfo,
45             int displayOrientation) {
46         super(context);
47 
48         // Do not initialise if no camera has been set
49         if (camera == null || cameraInfo == null) {
50             return;
51         }
52         mCamera = camera;
53         mCameraInfo = cameraInfo;
54         mDisplayOrientation = displayOrientation;
55 
56         // Install a SurfaceHolder.Callback so we get notified when the
57         // underlying surface is created and destroyed.
58         mHolder = getHolder();
59         mHolder.addCallback(this);
60     }
61 
surfaceCreated(SurfaceHolder holder)62     public void surfaceCreated(SurfaceHolder holder) {
63         // The Surface has been created, now tell the camera where to draw the preview.
64         try {
65             mCamera.setPreviewDisplay(holder);
66             mCamera.startPreview();
67             Log.d(TAG, "Camera preview started.");
68         } catch (IOException e) {
69             Log.d(TAG, "Error setting camera preview: " + e.getMessage());
70         }
71     }
72 
surfaceDestroyed(SurfaceHolder holder)73     public void surfaceDestroyed(SurfaceHolder holder) {
74         // empty. Take care of releasing the Camera preview in your activity.
75     }
76 
surfaceChanged(SurfaceHolder holder, int format, int w, int h)77     public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
78         // If your preview can change or rotate, take care of those events here.
79         // Make sure to stop the preview before resizing or reformatting it.
80 
81         if (mHolder.getSurface() == null) {
82             // preview surface does not exist
83             Log.d(TAG, "Preview surface does not exist");
84             return;
85         }
86 
87         // stop preview before making changes
88         try {
89             mCamera.stopPreview();
90             Log.d(TAG, "Preview stopped.");
91         } catch (Exception e) {
92             // ignore: tried to stop a non-existent preview
93             Log.d(TAG, "Error starting camera preview: " + e.getMessage());
94         }
95 
96         int orientation = calculatePreviewOrientation(mCameraInfo, mDisplayOrientation);
97         mCamera.setDisplayOrientation(orientation);
98 
99         try {
100             mCamera.setPreviewDisplay(mHolder);
101             mCamera.startPreview();
102             Log.d(TAG, "Camera preview started.");
103         } catch (Exception e) {
104             Log.d(TAG, "Error starting camera preview: " + e.getMessage());
105         }
106     }
107 
108     /**
109      * Calculate the correct orientation for a {@link Camera} preview that is displayed on screen.
110      *
111      * Implementation is based on the sample code provided in
112      * {@link Camera#setDisplayOrientation(int)}.
113      */
calculatePreviewOrientation(Camera.CameraInfo info, int rotation)114     public static int calculatePreviewOrientation(Camera.CameraInfo info, int rotation) {
115         int degrees = 0;
116 
117         switch (rotation) {
118             case Surface.ROTATION_0:
119                 degrees = 0;
120                 break;
121             case Surface.ROTATION_90:
122                 degrees = 90;
123                 break;
124             case Surface.ROTATION_180:
125                 degrees = 180;
126                 break;
127             case Surface.ROTATION_270:
128                 degrees = 270;
129                 break;
130         }
131 
132         int result;
133         if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
134             result = (info.orientation + degrees) % 360;
135             result = (360 - result) % 360;  // compensate the mirror
136         } else {  // back-facing
137             result = (info.orientation - degrees + 360) % 360;
138         }
139 
140         return result;
141     }
142 }
143