1 /*
2  * Copyright (C) 2013 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.common.media;
18 
19 import android.annotation.TargetApi;
20 import android.hardware.Camera;
21 import android.os.Build;
22 import android.os.Environment;
23 import android.util.Log;
24 
25 import java.io.File;
26 import java.text.SimpleDateFormat;
27 import java.util.Date;
28 import java.util.List;
29 
30 /**
31  * Camera related utilities.
32  */
33 public class CameraHelper {
34 
35     public static final int MEDIA_TYPE_IMAGE = 1;
36     public static final int MEDIA_TYPE_VIDEO = 2;
37 
38     /**
39      * Iterate over supported camera video sizes to see which one best fits the
40      * dimensions of the given view while maintaining the aspect ratio. If none can,
41      * be lenient with the aspect ratio.
42      *
43      * @param supportedVideoSizes Supported camera video sizes.
44      * @param previewSizes Supported camera preview sizes.
45      * @param w     The width of the view.
46      * @param h     The height of the view.
47      * @return Best match camera video size to fit in the view.
48      */
getOptimalVideoSize(List<Camera.Size> supportedVideoSizes, List<Camera.Size> previewSizes, int w, int h)49     public static Camera.Size getOptimalVideoSize(List<Camera.Size> supportedVideoSizes,
50             List<Camera.Size> previewSizes, int w, int h) {
51         // Use a very small tolerance because we want an exact match.
52         final double ASPECT_TOLERANCE = 0.1;
53         double targetRatio = (double) w / h;
54 
55         // Supported video sizes list might be null, it means that we are allowed to use the preview
56         // sizes
57         List<Camera.Size> videoSizes;
58         if (supportedVideoSizes != null) {
59             videoSizes = supportedVideoSizes;
60         } else {
61             videoSizes = previewSizes;
62         }
63         Camera.Size optimalSize = null;
64 
65         // Start with max value and refine as we iterate over available video sizes. This is the
66         // minimum difference between view and camera height.
67         double minDiff = Double.MAX_VALUE;
68 
69         // Target view height
70         int targetHeight = h;
71 
72         // Try to find a video size that matches aspect ratio and the target view size.
73         // Iterate over all available sizes and pick the largest size that can fit in the view and
74         // still maintain the aspect ratio.
75         for (Camera.Size size : videoSizes) {
76             double ratio = (double) size.width / size.height;
77             if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
78                 continue;
79             if (Math.abs(size.height - targetHeight) < minDiff && previewSizes.contains(size)) {
80                 optimalSize = size;
81                 minDiff = Math.abs(size.height - targetHeight);
82             }
83         }
84 
85         // Cannot find video size that matches the aspect ratio, ignore the requirement
86         if (optimalSize == null) {
87             minDiff = Double.MAX_VALUE;
88             for (Camera.Size size : videoSizes) {
89                 if (Math.abs(size.height - targetHeight) < minDiff && previewSizes.contains(size)) {
90                     optimalSize = size;
91                     minDiff = Math.abs(size.height - targetHeight);
92                 }
93             }
94         }
95         return optimalSize;
96     }
97 
98     /**
99      * @return the default camera on the device. Return null if there is no camera on the device.
100      */
getDefaultCameraInstance()101     public static Camera getDefaultCameraInstance() {
102         return Camera.open();
103     }
104 
105 
106     /**
107      * @return the default rear/back facing camera on the device. Returns null if camera is not
108      * available.
109      */
getDefaultBackFacingCameraInstance()110     public static Camera getDefaultBackFacingCameraInstance() {
111         return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
112     }
113 
114     /**
115      * @return the default front facing camera on the device. Returns null if camera is not
116      * available.
117      */
getDefaultFrontFacingCameraInstance()118     public static Camera getDefaultFrontFacingCameraInstance() {
119         return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_FRONT);
120     }
121 
122 
123     /**
124      *
125      * @param position Physical position of the camera i.e Camera.CameraInfo.CAMERA_FACING_FRONT
126      *                 or Camera.CameraInfo.CAMERA_FACING_BACK.
127      * @return the default camera on the device. Returns null if camera is not available.
128      */
129     @TargetApi(Build.VERSION_CODES.GINGERBREAD)
getDefaultCamera(int position)130     private static Camera getDefaultCamera(int position) {
131         // Find the total number of cameras available
132         int  mNumberOfCameras = Camera.getNumberOfCameras();
133 
134         // Find the ID of the back-facing ("default") camera
135         Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
136         for (int i = 0; i < mNumberOfCameras; i++) {
137             Camera.getCameraInfo(i, cameraInfo);
138             if (cameraInfo.facing == position) {
139                 return Camera.open(i);
140 
141             }
142         }
143 
144         return null;
145     }
146 
147     /**
148      * Creates a media file in the {@code Environment.DIRECTORY_PICTURES} directory. The directory
149      * is persistent and available to other applications like gallery.
150      *
151      * @param type Media type. Can be video or image.
152      * @return A file object pointing to the newly created file.
153      */
getOutputMediaFile(int type)154     public  static File getOutputMediaFile(int type){
155         // To be safe, you should check that the SDCard is mounted
156         // using Environment.getExternalStorageState() before doing this.
157         if (!Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED)) {
158             return  null;
159         }
160 
161         File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
162                 Environment.DIRECTORY_PICTURES), "CameraSample");
163         // This location works best if you want the created images to be shared
164         // between applications and persist after your app has been uninstalled.
165 
166         // Create the storage directory if it does not exist
167         if (! mediaStorageDir.exists()){
168             if (! mediaStorageDir.mkdirs()) {
169                 Log.d("CameraSample", "failed to create directory");
170                 return null;
171             }
172         }
173 
174         // Create a media file name
175         String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
176         File mediaFile;
177         if (type == MEDIA_TYPE_IMAGE){
178             mediaFile = new File(mediaStorageDir.getPath() + File.separator +
179                     "IMG_"+ timeStamp + ".jpg");
180         } else if(type == MEDIA_TYPE_VIDEO) {
181             mediaFile = new File(mediaStorageDir.getPath() + File.separator +
182                     "VID_"+ timeStamp + ".mp4");
183         } else {
184             return null;
185         }
186 
187         return mediaFile;
188     }
189 
190 }
191