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