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