package nz.co.android.cowseye.view; import java.io.IOException; import java.util.List; import nz.co.android.cowseye.R; import nz.co.android.cowseye.common.Constants; import nz.co.android.cowseye.utility.Utils; import android.app.Activity; import android.content.Context; import android.hardware.Camera; import android.hardware.Camera.Parameters; import android.hardware.Camera.PreviewCallback; import android.hardware.Camera.Size; import android.util.Log; import android.view.Display; import android.view.Gravity; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.ViewParent; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.Toast; public class Preview extends SurfaceView implements SurfaceHolder.Callback { private static final String TAG = "Preview"; private SurfaceHolder mHolder; public Camera camera; private boolean correctPictureSizeSet; private boolean resizedFrame = false; private double ASPECT_RATIO_WIDTH = 4.00; private double ASPECT_RATIO_HEIGHT = 3.00; private boolean isPreviewRunning = false; private final Display display; private final Activity parentActivity; public Preview(Activity parentActivity, Display display) { super(parentActivity); this.display = display; this.parentActivity = parentActivity; correctPictureSizeSet = false; // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = getHolder(); mHolder.addCallback(this); mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void surfaceCreated(SurfaceHolder holder) { Log.e(toString(), " surfaceCreated :"+holder); // The Surface has been created, acquire the camera and tell it where // to draw. try { // This case can actually happen if the user opens and closes the camera too frequently. // The problem is that we cannot really prevent this from happening as the user can easily // get into a chain of activities and tries to escape using the back button. // The most sensible solution would be to quit the entire EPostcard flow once the picture is sent. camera = Camera.open(); } catch(Exception e) { Log.e(toString(), "Failed to open camera : "+e); Toast.makeText(parentActivity, parentActivity.getString(R.string.failed_to_connect_to_camera_message), Toast.LENGTH_LONG).show(); parentActivity.finish(); return; } try { camera.setPreviewDisplay(holder); } catch (IOException e) { e.printStackTrace(); Log.e(toString(), "could not set preview display"); } camera.setPreviewCallback(null); } public void surfaceDestroyed(SurfaceHolder holder) { // Surface will be destroyed when we return, so stop the preview. // Because the CameraDevice object is not a shared resource, it's very // important to release it when the activity is paused. Log.e(toString(), "Surface destroyed!"); if (camera != null) { camera.stopPreview(); camera.setPreviewCallback(null); camera.release(); camera = null; } } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // Now that the size is known, set up the camera parameters and begin // the preview. if(camera==null) return; if (isPreviewRunning) { camera.stopPreview(); isPreviewRunning = false; } Parameters parameters = camera.getParameters(); if(display.getRotation() == Surface.ROTATION_0) { // parameters.setPreviewSize(h, w); setPreviewSize(h, w, parameters, false); setPictureSize(Constants.IMAGE_HEIGHT, Constants.IMAGE_WIDTH, parameters); camera.setDisplayOrientation(90); } if(display.getRotation() == Surface.ROTATION_90) { // parameters.setPreviewSize(w, h); setPreviewSize(w, h, parameters, true); setPictureSize(Constants.IMAGE_WIDTH, Constants.IMAGE_HEIGHT, parameters); } if(display.getRotation() == Surface.ROTATION_180) { // parameters.setPreviewSize(h, w); setPreviewSize(h, w, parameters, false); setPictureSize(Constants.IMAGE_HEIGHT, Constants.IMAGE_WIDTH, parameters); } if(display.getRotation() == Surface.ROTATION_270) { // parameters.setPreviewSize(w, h); setPreviewSize(w, h, parameters, true); setPictureSize(Constants.IMAGE_WIDTH,Constants.IMAGE_HEIGHT, parameters); camera.setDisplayOrientation(180); } // parameters.getP // camera.setParameters(parameters); previewCamera(); // Camera.Parameters parameters = camera.getParameters(); // setPreviewSize(w, h, parameters); // camera.startPreview(); } public void previewCamera() { try { camera.startPreview(); isPreviewRunning = true; } catch(Exception e) { Log.d(toString(), "Cannot start preview", e); } } private void setPreviewSize(int w, int h, Camera.Parameters parameters, boolean horizontal) { try{ parameters.setPreviewSize(w, h); camera.setParameters(parameters); } catch(RuntimeException e){ Log.e(toString(), "Setting preview size initialy failed, trying alternative"); Size s = findBestPreviewSize(h, w); try{ if(horizontal) parameters.setPreviewSize(s.width, s.height); else parameters.setPreviewSize(s.height, s.width); } catch(RuntimeException f){ Log.e(toString(), "Second setting of preview size failed: "+f); } } // Log.d(toString(), "resizing frame b4"); //if measured then don't resize frame if(!resizedFrame && horizontal){ resizedFrame = true; //set parents dimensions to keep aspect ratio of 4:4 ViewParent vp = getParent(); FrameLayout f = (FrameLayout)vp; double frameWd = f.getMeasuredWidth()+.00; double frameHt = f.getMeasuredHeight()+.00; int newWd = (int)frameWd; int newHt = (int)frameHt; //Too high, reduce y if((frameHt/frameWd) > (ASPECT_RATIO_WIDTH/ASPECT_RATIO_HEIGHT)){ newHt = (int)(frameWd*4/3); } //Too long, reduce X else{ newWd = (int)(frameHt*4/3); } if(horizontal) f.setLayoutParams(new FrameLayout.LayoutParams(newWd, newHt,Gravity.CENTER)); else f.setLayoutParams(new FrameLayout.LayoutParams(newHt, newWd,Gravity.CENTER)); } } private void setPictureSize(int w, int h, Camera.Parameters parameters) { try{ parameters.setPictureSize(Constants.IMAGE_WIDTH, Constants.IMAGE_HEIGHT); camera.setParameters(parameters); correctPictureSizeSet = true; Log.e(toString(), "wd : "+Constants.IMAGE_WIDTH+", "+Constants.IMAGE_HEIGHT); } catch(RuntimeException e){ Log.e(toString(), "Setting picture size initialy failed, trying alternative"); Size s = findBestPictureSize(Constants.IMAGE_WIDTH, Constants.IMAGE_HEIGHT); try{ parameters.setPictureSize(s.width, s.height); Log.e(toString(), "wd : "+s.width+", "+s.height); } catch(RuntimeException f){ correctPictureSizeSet = false; Log.e(toString(), "Second setting of picture size failed: "+f); } } } private Size findBestPreviewSize(int desiredWidth, int desiredHeight){ // Log.d(toString(), "in findBestPreviewSize"); int newWidth = Integer.MAX_VALUE; int newHeight = Integer.MAX_VALUE; int bestError = Integer.MAX_VALUE; boolean bestHasRatio = false; Camera.Parameters parameters = camera.getParameters(); List<Size> previewSizes = parameters.getSupportedPreviewSizes(); if(previewSizes!=null && previewSizes.size()>0){ Size s = previewSizes.get(0); newWidth = s.width; newHeight = s.height; bestError = 0; bestError+= Math.abs(s.width - desiredWidth); bestError+= Math.abs(s.height - desiredHeight); if((newWidth+0.00)/(newHeight+0.00) > 0.749 && (newWidth+0.00)/(newHeight+0.00) < 0.751 || (newHeight+0.00)/(newWidth+0.00) > 0.749 && (newHeight+0.00)/(newWidth+0.00) < 0.751 ) bestHasRatio = true; } for(int i = 1; i < previewSizes.size(); i++){ Size s = previewSizes.get(i); int error = 0; error+= Math.abs(s.width - desiredWidth); error+= Math.abs(s.height - desiredHeight); if(!bestHasRatio){ if(error<bestError){ bestError = error; newWidth = s.width; newHeight = s.height; bestHasRatio = ((newWidth+0.00)/(newHeight+0.00) > 0.749 && (newWidth+0.00)/(newHeight+0.00) < 0.751 || (newHeight+0.00)/(newWidth+0.00) > 0.749 && (newHeight+0.00)/(newWidth+0.00) < 0.751 ); } } else if(error<bestError){ boolean localRatio = false; if((s.width+0.00)/(s.height+0.00) > 0.749 && (s.width+0.00)/(s.height+0.00) < 0.751 || (s.height+0.00)/(s.width+0.00) > 0.749 && (s.height+0.00)/(s.width+0.00) < 0.751 ) localRatio = true; if(localRatio){ bestError = error; newWidth = s.width; newHeight = s.height; } } } if(newWidth == Integer.MAX_VALUE) newWidth = desiredWidth; if(newHeight == Integer.MAX_VALUE) newHeight = desiredHeight; return camera.new Size(newWidth, newHeight); } private Size findBestPictureSize(int desiredWidth, int desiredHeight){ int newWidth = Integer.MAX_VALUE; int newHeight = Integer.MAX_VALUE; int bestError = Integer.MAX_VALUE; Camera.Parameters parameters = camera.getParameters(); List<Size> pictureSizes = parameters.getSupportedPictureSizes(); if(pictureSizes!=null && pictureSizes.size()>0){ Size s = pictureSizes.get(0); newWidth = s.width; newHeight = s.height; bestError = 0; bestError+= Math.abs(s.width - desiredWidth); bestError+= Math.abs(s.height - desiredHeight); } for(int i = 1; i < pictureSizes.size(); i++){ Size s = pictureSizes.get(i); int error = 0; error+= Math.abs(s.width - desiredWidth); error+= Math.abs(s.height - desiredHeight); if(error<bestError){ bestError = error; newWidth = s.width; newHeight = s.height; } } if(newWidth == Integer.MAX_VALUE){ newWidth = desiredWidth; correctPictureSizeSet = false; } if(newHeight == Integer.MAX_VALUE){ newHeight = desiredHeight; correctPictureSizeSet = false; } return camera.new Size(newWidth, newHeight); } }