Java tutorial
package com.glenn.cresco.photosharingsample.fragments; /* * Copyright (c) 2014 Rex St. John on behalf of AirPair.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ import android.content.Context; import android.content.Intent; import android.hardware.Camera; import android.os.Bundle; import android.support.v4.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; import com.glenn.cresco.photosharingsample.PhotoSendActivity; import com.glenn.cresco.photosharingsample.R; import com.glenn.cresco.photosharingsample.utils.PictureUtils; import java.util.List; import java.util.concurrent.Callable; import bolts.Continuation; import bolts.Task; import butterknife.Bind; import butterknife.ButterKnife; /** * Created by Glenn on 12/01/2016. */ public class PhotoCameraFragment extends Fragment { public static final String TAG = PhotoCameraFragment.class.getSimpleName(); public static final String CAMERA_ID_KEY = "camera_id"; public static final String CAMERA_FLASH_KEY = "flash_mode"; public static final String IMAGE_INFO = "image_info"; private static final int PICTURE_SIZE_MAX_WIDTH = 1280; private static final int PREVIEW_SIZE_MAX_WIDTH = 640; @Bind(R.id.capture_image_button) ImageView captureButton; @Bind(R.id.flash) View flashGroup; @Bind(R.id.change_camera) ImageView swapCameraBtn; // Native camera. private Camera mCamera; // View to display the camera output. private CameraPreview mPreview; // Reference to the containing view. private View mCameraView; /** * Default empty constructor. */ public PhotoCameraFragment() { super(); } public static PhotoCameraFragment newInstance() { return new PhotoCameraFragment(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_photo_camera, container, false); ButterKnife.bind(this, view); // Create our Preview view and set it as the content of our activity. boolean opened = safeCameraOpenInView(view); if (!opened) { Log.d("CameraGuide", "Error, Camera failed to open"); return view; } // Trap the capture button. captureButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // get an image from the camera mCamera.takePicture(null, null, mPicture); } }); return view; } /** * Recommended "safe" way to open the camera. * * @param view * @return */ private boolean safeCameraOpenInView(View view) { boolean qOpened; releaseCameraAndPreview(); mCamera = getCameraInstance(); mCameraView = view; qOpened = (mCamera != null); if (qOpened) { mPreview = new CameraPreview(getActivity().getBaseContext(), mCamera); FrameLayout preview = (FrameLayout) view.findViewById(R.id.camera_preview); preview.addView(mPreview); mPreview.startCameraPreview(); } return qOpened; } /** * Safe method for getting a camera instance. * * @return */ public static Camera getCameraInstance() { Camera c = null; try { c = Camera.open(); // attempt to get a Camera instance } catch (Exception e) { e.printStackTrace(); } return c; // returns null if camera is unavailable } @Override public void onPause() { super.onPause(); releaseCameraAndPreview(); } @Override public void onDestroy() { super.onDestroy(); releaseCameraAndPreview(); } /** * Clear any existing preview / camera. */ private void releaseCameraAndPreview() { if (mCamera != null) { mCamera.stopPreview(); mCamera.release(); mCamera = null; } if (mPreview != null) { mPreview.destroyDrawingCache(); mPreview.mCamera = null; } } /** * Picture Callback for handling a picture capture and saving it out to a file. */ private Camera.PictureCallback mPicture = new Camera.PictureCallback() { @Override public void onPictureTaken(final byte[] data, Camera camera) { Log.d("picture taken", "taken"); Task.callInBackground(new Callable<Void>() { @Override public Void call() throws Exception { PictureUtils.saveBitmapToCache(data, getActivity()); return null; } }).onSuccess(new Continuation<Void, Void>() { @Override public Void then(Task<Void> task) throws Exception { Intent intent = new Intent(getActivity(), PhotoSendActivity.class); startActivity(intent); return null; } }); } }; public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { private static final String TAG = "CameraPreview"; private Context mContext; private SurfaceHolder mHolder; private Camera mCamera; private List<Camera.Size> mSupportedPreviewSizes; private Camera.Size mPreviewSize; public CameraPreview(Context context, Camera camera) { super(context); mContext = context; mCamera = camera; // supported preview sizes mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes(); for (Camera.Size str : mSupportedPreviewSizes) Log.e(TAG, str.width + "/" + str.height); // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = getHolder(); mHolder.addCallback(this); // deprecated setting, but required on Android versions prior to 3.0 mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void surfaceCreated(SurfaceHolder holder) { // empty. surfaceChanged will take care of stuff } public void surfaceDestroyed(SurfaceHolder holder) { // empty. Take care of releasing the Camera preview in your activity. } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { Log.e(TAG, "surfaceChanged => w=" + w + ", h=" + h); // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (mHolder.getSurface() == null) { // preview surface does not exist return; } // stop preview before making changes try { mCamera.stopPreview(); } catch (Exception e) { // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or reformatting changes here // start preview with new settings try { Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); mCamera.setParameters(parameters); mCamera.setDisplayOrientation(90); mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e) { Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); if (mSupportedPreviewSizes != null) { mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height); } float ratio; if (mPreviewSize.height >= mPreviewSize.width) ratio = (float) mPreviewSize.height / (float) mPreviewSize.width; else ratio = (float) mPreviewSize.width / (float) mPreviewSize.height; float camHeight = (int) (width * ratio); float newCamHeight; float newHeightRatio; if (camHeight < height) { newHeightRatio = (float) height / (float) mPreviewSize.height; newCamHeight = (newHeightRatio * camHeight); Log.e(TAG, camHeight + " " + height + " " + mPreviewSize.height + " " + newHeightRatio + " " + newCamHeight); setMeasuredDimension((int) (width * newHeightRatio), (int) newCamHeight); Log.e(TAG, mPreviewSize.width + " | " + mPreviewSize.height + " | ratio - " + ratio + " | H_ratio - " + newHeightRatio + " | A_width - " + (width * newHeightRatio) + " | A_height - " + newCamHeight); } else { newCamHeight = camHeight; setMeasuredDimension(width, (int) newCamHeight); Log.e(TAG, mPreviewSize.width + " | " + mPreviewSize.height + " | ratio - " + ratio + " | A_width - " + (width) + " | A_height - " + newCamHeight); } // One of these methods should be used, second method squishes preview slightly setMeasuredDimension(width, (int) (width * ratio)); // setMeasuredDimension((int) (width * ratio), height); } private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.1; double targetRatio = (double) h / w; if (sizes == null) return null; Camera.Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; for (Camera.Size size : sizes) { double ratio = (double) size.height / size.width; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Camera.Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; } public void startCameraPreview() { try { mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e) { e.printStackTrace(); } } } /** * Surface on which the camera projects it's capture results. This is derived both from Google's docs and the * excellent StackOverflow answer provided below. * <p/> * Reference / Credit: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { // SurfaceHolder private SurfaceHolder mHolder; // Our Camera. private Camera mCamera; // Parent Context. private Context mContext; // Camera Sizing (For rotation, orientation changes) private Camera.Size mPreviewSize; // List of supported preview sizes private List<Camera.Size> mSupportedPreviewSizes; // Flash modes supported by this camera private List<String> mSupportedFlashModes; // View holding this camera. private View mCameraView; public CameraPreview(Context context, Camera camera, View cameraView) { super(context); // Capture the context mCameraView = cameraView; mContext = context; setCamera(camera); // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = getHolder(); mHolder.addCallback(this); mHolder.setKeepScreenOn(true); // deprecated setting, but required on Android versions prior to 3.0 mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void startCameraPreview() { try { mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e) { e.printStackTrace(); } } private void setCamera(Camera camera) { // Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails mCamera = camera; mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes(); mSupportedFlashModes = mCamera.getParameters().getSupportedFlashModes(); // Set the camera to Auto Flash mode. if (mSupportedFlashModes != null && mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)) { Camera.Parameters parameters = mCamera.getParameters(); parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO); mCamera.setParameters(parameters); } requestLayout(); } public void surfaceCreated(SurfaceHolder holder) { try { mCamera.setPreviewDisplay(holder); mCamera.setDisplayOrientation(90); } catch (IOException e) { e.printStackTrace(); } } public void surfaceDestroyed(SurfaceHolder holder) { if (mCamera != null) { mCamera.stopPreview(); } } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (mHolder.getSurface() == null) { // preview surface does not exist return; } // stop preview before making changes try { Camera.Parameters parameters = mCamera.getParameters(); // Set the auto-focus mode to "continuous" parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); // Preview size must exist. if (mPreviewSize != null) { Camera.Size previewSize = mPreviewSize; parameters.setPreviewSize(previewSize.width, previewSize.height); } mCamera.setParameters(parameters); mCamera.startPreview(); } catch (Exception e) { e.printStackTrace(); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); setMeasuredDimension(width, height); if (mSupportedPreviewSizes != null) { mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height); } } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { // Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails if (changed) { final int width = right - left; final int height = bottom - top; int previewWidth = width; int previewHeight = height; if (mPreviewSize != null) { previewWidth = mPreviewSize.height; previewHeight = mPreviewSize.width; mCamera.setDisplayOrientation(90); } final int scaledChildHeight = previewHeight * width / previewWidth; mCameraView.layout(0, height - scaledChildHeight, width, height); } } private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.1; double targetRatio = (double) h / w; if (sizes == null) return null; Camera.Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; for (Camera.Size size : sizes) { double ratio = (double) size.width / size.height; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Camera.Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; } }*/ }