Java tutorial
/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.mariachi.allianzvision.camera.api14; import android.annotation.SuppressLint; import android.graphics.SurfaceTexture; import android.hardware.Camera; import android.os.Build; import android.support.v4.util.SparseArrayCompat; import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.View; import java.io.IOException; import java.util.List; import java.util.Set; import java.util.SortedSet; import io.mariachi.allianzvision.camera.base.AspectRatio; import io.mariachi.allianzvision.camera.base.CameraViewImpl; import io.mariachi.allianzvision.camera.base.Constants; import io.mariachi.allianzvision.camera.base.PreviewImpl; import io.mariachi.allianzvision.camera.base.Size; import io.mariachi.allianzvision.camera.base.SizeMap; @SuppressWarnings("deprecation") public class Camera1 extends CameraViewImpl implements View.OnTouchListener { private static final int INVALID_CAMERA_ID = -1; private static final SparseArrayCompat<String> FLASH_MODES = new SparseArrayCompat<>(); static { FLASH_MODES.put(Constants.FLASH_OFF, Camera.Parameters.FLASH_MODE_OFF); FLASH_MODES.put(Constants.FLASH_ON, Camera.Parameters.FLASH_MODE_ON); FLASH_MODES.put(Constants.FLASH_TORCH, Camera.Parameters.FLASH_MODE_TORCH); FLASH_MODES.put(Constants.FLASH_AUTO, Camera.Parameters.FLASH_MODE_AUTO); FLASH_MODES.put(Constants.FLASH_RED_EYE, Camera.Parameters.FLASH_MODE_RED_EYE); } private int mCameraId; Camera mCamera; private Camera.Parameters mCameraParameters; private final Camera.CameraInfo mCameraInfo = new Camera.CameraInfo(); private final SizeMap mPreviewSizes = new SizeMap(); private final SizeMap mPictureSizes = new SizeMap(); private AspectRatio mAspectRatio; private boolean mShowingPreview; private boolean mAutoFocus; private int mFacing; private int mFlash; private int mDisplayOrientation; private float mDistance; public Camera1(Callback callback, PreviewImpl preview) { super(callback, preview); preview.setCallback(new PreviewImpl.Callback() { @Override public void onSurfaceChanged() { if (mCamera != null) { setUpPreview(); adjustCameraParameters(); } } }); } @Override public boolean start() { chooseCamera(); openCamera(); if (mPreview.isReady()) { setUpPreview(); } mShowingPreview = true; mCamera.startPreview(); return true; } @Override public void stop() { if (mCamera != null) { mCamera.stopPreview(); } mShowingPreview = false; releaseCamera(); } // Suppresses Camera#setPreviewTexture @SuppressLint("NewApi") void setUpPreview() { try { if (mPreview.getOutputClass() == SurfaceHolder.class) { final boolean needsToStopPreview = mShowingPreview && Build.VERSION.SDK_INT < 14; if (needsToStopPreview) { mCamera.stopPreview(); } // mCamera.setPreviewDisplay(mPreview.getSurfaceHolder()); // mCamera.setPreviewCallback(new Camera.PreviewCallback() { // @Override // public void onPreviewFrame(byte[] bytes, Camera camera) { // mCallback.onPreviewFrame(bytes); // } // }); if (needsToStopPreview) { mCamera.startPreview(); } } else { mCamera.setPreviewTexture((SurfaceTexture) mPreview.getSurfaceTexture()); } } catch (IOException e) { throw new RuntimeException(e); } } @Override public boolean isCameraOpened() { return mCamera != null; } @Override public void setFacing(int facing) { if (mFacing == facing) { return; } mFacing = facing; if (isCameraOpened()) { stop(); start(); } } @Override public int getFacing() { return mFacing; } @Override public Set<AspectRatio> getSupportedAspectRatios() { return mPreviewSizes.ratios(); } @Override public boolean setAspectRatio(AspectRatio ratio) { if (mAspectRatio == null || !isCameraOpened()) { // Handle this later when camera is opened mAspectRatio = ratio; return true; } else if (!mAspectRatio.equals(ratio)) { final Set<Size> sizes = mPreviewSizes.sizes(ratio); if (sizes == null) { throw new UnsupportedOperationException(ratio + " is not supported"); } else { mAspectRatio = ratio; adjustCameraParameters(); return true; } } return false; } @Override public AspectRatio getAspectRatio() { return mAspectRatio; } @Override public void setAutoFocus(boolean autoFocus) { if (mAutoFocus == autoFocus) { return; } if (setAutoFocusInternal(autoFocus)) { mCamera.setParameters(mCameraParameters); } } @Override public boolean getAutoFocus() { if (!isCameraOpened()) { return mAutoFocus; } String focusMode = mCameraParameters.getFocusMode(); return focusMode != null && focusMode.contains("continuous"); } @Override public void setFlash(int flash) { if (flash == mFlash) { return; } if (setFlashInternal(flash)) { mCamera.setParameters(mCameraParameters); } } @Override public int getFlash() { return mFlash; } @Override public void takePicture() { if (!isCameraOpened()) { throw new IllegalStateException("Camera is not ready. Call start() before takePicture()."); } if (getAutoFocus()) { mCamera.cancelAutoFocus(); mCamera.autoFocus(new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { takePictureInternal(); } }); } else { takePictureInternal(); } } public void takePictureInternal() { mCamera.takePicture(null, null, null, new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { mCallback.onPictureTaken(data); camera.cancelAutoFocus(); camera.startPreview(); } }); } @Override public void setDisplayOrientation(int displayOrientation) { if (mDisplayOrientation == displayOrientation) { return; } mDisplayOrientation = displayOrientation; if (isCameraOpened()) { int cameraRotation = calcCameraRotation(displayOrientation); mCameraParameters.setRotation(cameraRotation); mCamera.setParameters(mCameraParameters); final boolean needsToStopPreview = mShowingPreview && Build.VERSION.SDK_INT < 14; if (needsToStopPreview) { mCamera.stopPreview(); } mCamera.setDisplayOrientation(cameraRotation); if (needsToStopPreview) { mCamera.startPreview(); } } } /** * This rewrites {@link #mCameraId} and {@link #mCameraInfo}. */ private void chooseCamera() { for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) { Camera.getCameraInfo(i, mCameraInfo); if (mCameraInfo.facing == mFacing) { mCameraId = i; return; } } mCameraId = INVALID_CAMERA_ID; } private void openCamera() { if (mCamera != null) { releaseCamera(); } mCamera = Camera.open(mCameraId); mCameraParameters = mCamera.getParameters(); // Supported preview sizes mPreviewSizes.clear(); for (Camera.Size size : mCameraParameters.getSupportedPreviewSizes()) { mPreviewSizes.add(new Size(size.width, size.height)); } // Supported picture sizes; mPictureSizes.clear(); for (Camera.Size size : mCameraParameters.getSupportedPictureSizes()) { mPictureSizes.add(new Size(size.width, size.height)); } // AspectRatio if (mAspectRatio == null) { mAspectRatio = Constants.DEFAULT_ASPECT_RATIO; } adjustCameraParameters(); mCamera.setDisplayOrientation(calcCameraRotation(mDisplayOrientation)); mCallback.onCameraOpened(); } private AspectRatio chooseAspectRatio() { AspectRatio r = null; for (AspectRatio ratio : mPreviewSizes.ratios()) { r = ratio; if (ratio.equals(Constants.DEFAULT_ASPECT_RATIO)) { return ratio; } } return r; } public void adjustCameraParameters() { SortedSet<Size> sizes = mPreviewSizes.sizes(mAspectRatio); if (sizes == null) { // Not supported mAspectRatio = chooseAspectRatio(); sizes = mPreviewSizes.sizes(mAspectRatio); } Size size = chooseOptimalSize(sizes); final Camera.Size currentSize = mCameraParameters.getPictureSize(); if (currentSize.width != size.getWidth() || currentSize.height != size.getHeight()) { // Largest picture size in this ratio final Size pictureSize = mPictureSizes.sizes(mAspectRatio).last(); if (mShowingPreview) { mCamera.stopPreview(); } mCameraParameters.setPreviewSize(size.getWidth(), size.getHeight()); mCameraParameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight()); mCameraParameters.setRotation(calcCameraRotation(mDisplayOrientation)); //ken mCameraParameters.setPreviewFpsRange(29000, 29000); setAutoFocusInternal(mAutoFocus); setFlashInternal(mFlash); mCamera.setParameters(mCameraParameters); mPreview.setOnTouchEvent(this); try { mCamera.setPreviewDisplay(mPreview.getSurfaceHolder()); log("Se le asigno el preview"); } catch (IOException e) { e.printStackTrace(); } // try { // mCamera.setPreviewDisplay(mPreview.getSurfaceHolder()); // } catch (Exception e) { // e.printStackTrace(); // return; // } if (mShowingPreview) { mCamera.setPreviewCallback(new Camera.PreviewCallback() { @Override public void onPreviewFrame(byte[] bytes, Camera camera) { mCallback.onPreviewFrame(bytes); } }); mCamera.startPreview(); } } } @SuppressWarnings("SuspiciousNameCombination") private Size chooseOptimalSize(SortedSet<Size> sizes) { if (!mPreview.isReady()) { // Not yet laid out return sizes.first(); // Return the smallest size } int desiredWidth; int desiredHeight; final int surfaceWidth = mPreview.getWidth(); final int surfaceHeight = mPreview.getHeight(); if (mDisplayOrientation == 90 || mDisplayOrientation == 270) { desiredWidth = surfaceHeight; desiredHeight = surfaceWidth; } else { desiredWidth = surfaceWidth; desiredHeight = surfaceHeight; } Size result = null; for (Size size : sizes) { // Iterate from small to large if (desiredWidth <= size.getWidth() && desiredHeight <= size.getHeight()) { return size; } result = size; } return result; } private void releaseCamera() { if (mCamera != null) { mCamera.setPreviewCallback(null); mCamera.release(); mCamera = null; mCallback.onCameraClosed(); } } private int calcCameraRotation(int rotation) { if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { return (360 - (mCameraInfo.orientation + rotation) % 360) % 360; } else { // back-facing return (mCameraInfo.orientation - rotation + 360) % 360; } } /** * @return {@code true} if {@link #mCameraParameters} was modified. */ private boolean setAutoFocusInternal(boolean autoFocus) { mAutoFocus = autoFocus; if (isCameraOpened()) { final List<String> modes = mCameraParameters.getSupportedFocusModes(); if (autoFocus && modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); } else if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) { mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED); } else if (modes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) { mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY); } else { mCameraParameters.setFocusMode(modes.get(0)); } return true; } else { return false; } } /** * @return {@code true} if {@link #mCameraParameters} was modified. */ private boolean setFlashInternal(int flash) { if (isCameraOpened()) { List<String> modes = mCameraParameters.getSupportedFlashModes(); String mode = FLASH_MODES.get(flash); if (modes != null && modes.contains(mode)) { mCameraParameters.setFlashMode(mode); mFlash = flash; return true; } String currentMode = FLASH_MODES.get(mFlash); if (modes == null || !modes.contains(currentMode)) { mCameraParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); mFlash = Constants.FLASH_OFF; return true; } return false; } else { mFlash = flash; return false; } } public void log(String content) { Log.d("myLog", content); } @Override public boolean onTouch(View view, MotionEvent event) { Log.e("log", "touchevent"); Camera.Parameters params = mCamera.getParameters(); int action = event.getAction(); if (event.getPointerCount() > 1) { if (action == MotionEvent.ACTION_POINTER_DOWN) { mDistance = getFingerSpacing(event); } else if (action == MotionEvent.ACTION_MOVE && params.isZoomSupported()) { mCamera.cancelAutoFocus(); handleZoom(event, params); } } else { // handle single touch events if (action == MotionEvent.ACTION_UP) { handleFocus(event, params); } } return true; } public void handleFocus(MotionEvent event, Camera.Parameters params) { int pointerId = event.getPointerId(0); int pointerIndex = event.findPointerIndex(pointerId); // Get the pointer's current position float x = event.getX(pointerIndex); float y = event.getY(pointerIndex); List<String> supportedFocusModes = params.getSupportedFocusModes(); if (supportedFocusModes != null && supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { mCamera.autoFocus(new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean b, Camera camera) { // currently set to auto-focus on single touch } }); } } /** * Determine the space between the first two fingers */ private float getFingerSpacing(MotionEvent event) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return (float) Math.sqrt(x * x + y * y); } private void handleZoom(MotionEvent event, Camera.Parameters params) { int maxZoom = params.getMaxZoom(); int zoom = params.getZoom(); float newDist = getFingerSpacing(event); if (newDist > mDistance) { //zoom in if (zoom < maxZoom) zoom++; } else if (newDist < mDistance) { //zoom out if (zoom > 0) zoom--; } mDistance = newDist; params.setZoom(zoom); mCamera.setParameters(params); } }