| /* |
| * Copyright (C) 2015 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 com.android.example.cannylive; |
| |
| import android.content.Context; |
| import android.graphics.ImageFormat; |
| import android.hardware.camera2.CameraAccessException; |
| import android.hardware.camera2.CameraCaptureSession; |
| import android.hardware.camera2.CameraCharacteristics; |
| import android.hardware.camera2.CameraDevice; |
| import android.hardware.camera2.CameraManager; |
| import android.hardware.camera2.CaptureRequest; |
| import android.hardware.camera2.TotalCaptureResult; |
| import android.hardware.camera2.params.StreamConfigurationMap; |
| import android.media.Image; |
| import android.media.ImageReader; |
| import android.os.ConditionVariable; |
| import android.os.Handler; |
| import android.os.HandlerThread; |
| import android.os.Looper; |
| import android.util.Log; |
| import android.util.Range; |
| import android.util.Size; |
| import android.view.Surface; |
| import android.view.SurfaceHolder; |
| |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.nio.ByteBuffer; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.List; |
| |
| /** |
| * Simple interface for operating the camera, with major camera operations |
| * all performed on a background handler thread. |
| */ |
| public class CameraOps { |
| |
| private static final String TAG = "CameraOps"; |
| private static final long ONE_SECOND = 1000000000; |
| public static final long CAMERA_CLOSE_TIMEOUT = 2000; // ms |
| |
| private final CameraManager mCameraManager; |
| private CameraDevice mCameraDevice; |
| private CameraCaptureSession mCameraSession; |
| private List<Surface> mSurfaces; |
| |
| private final ConditionVariable mCloseWaiter = new ConditionVariable(); |
| |
| private HandlerThread mCameraThread; |
| private Handler mCameraHandler; |
| |
| private final ErrorDisplayer mErrorDisplayer; |
| |
| private final CameraReadyListener mReadyListener; |
| private final Handler mReadyHandler; |
| |
| private int mISOmax; |
| private int mISOmin; |
| private long mExpMax; |
| private long mExpMin; |
| private float mFocusMin; |
| private float mFocusDist = 0; |
| private int mIso; |
| boolean mAutoExposure = true; |
| boolean mAutoFocus = true; |
| private long mExposure = ONE_SECOND / 33; |
| |
| private Object mAutoExposureTag = new Object(); |
| |
| private ImageReader mImageReader; |
| private Handler mBackgroundHandler; |
| private CameraCharacteristics mCameraInfo; |
| private HandlerThread mBackgroundThread; |
| CaptureRequest.Builder mHdrBuilder; |
| private Surface mProcessingNormalSurface; |
| CaptureRequest mPreviewRequest; |
| private String mSaveFileName; |
| private Context mContext; |
| private int mCaptureMode; |
| |
| public String resume() { |
| String errorMessage = "Unknown error"; |
| boolean foundCamera = false; |
| try { |
| // Find first back-facing camera that has necessary capability |
| String[] cameraIds = mCameraManager.getCameraIdList(); |
| for (String id : cameraIds) { |
| CameraCharacteristics info = mCameraManager.getCameraCharacteristics(id); |
| int facing = info.get(CameraCharacteristics.LENS_FACING); |
| |
| int level = info.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); |
| boolean hasFullLevel |
| = (level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL); |
| |
| int[] capabilities = info.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); |
| int syncLatency = info.get(CameraCharacteristics.SYNC_MAX_LATENCY); |
| boolean hasManualControl = hasCapability(capabilities, |
| CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR); |
| boolean hasEnoughCapability = hasManualControl && |
| syncLatency == CameraCharacteristics.SYNC_MAX_LATENCY_PER_FRAME_CONTROL; |
| Range<Integer> irange; |
| Range<Long> lrange; |
| |
| irange = info.get(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE); |
| if (irange != null) { |
| mISOmax = irange.getUpper(); |
| mISOmin = irange.getLower(); |
| lrange = info.get(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE); |
| mExpMax = lrange.getUpper(); |
| mExpMin = lrange.getLower(); |
| mFocusMin = info.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE); |
| } else { |
| mISOmax = 200; |
| mISOmin = 100; |
| mExpMax = 1000; |
| } |
| mFocusDist = mFocusMin; |
| StreamConfigurationMap map = info.get( |
| CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); |
| Size[] sizes = map.getOutputSizes(ImageFormat.JPEG); |
| List<Size> sizeList = Arrays.asList(sizes); |
| Collections.sort(sizeList, new Comparator<Size>() { |
| @Override |
| public int compare(Size lhs, Size rhs) { |
| int leftArea = lhs.getHeight() * lhs.getWidth(); |
| int rightArea = lhs.getHeight() * lhs.getWidth(); |
| return Integer.compare(leftArea, rightArea); |
| } |
| }); |
| Size max = sizeList.get(0); |
| int check = 1; |
| Size big = sizeList.get(check); |
| float aspect = 16/9f; |
| Log.v(TAG,"max big "+max.getWidth()+" x "+max.getHeight()); |
| for (int i = 0; i < sizeList.size(); i++) { |
| Size s = sizeList.get(i); |
| if (s.getHeight() == 720) { |
| big = s; |
| break; |
| } |
| } |
| Log.v(TAG,"BIG wil be "+big.getWidth()+" x "+big.getHeight()); |
| mImageReader = ImageReader.newInstance(big.getWidth(), big.getHeight(), |
| ImageFormat.JPEG, /*maxImages*/2); |
| mImageReader.setOnImageAvailableListener( |
| mOnImageAvailableListener, mBackgroundHandler); |
| |
| if (facing == CameraCharacteristics.LENS_FACING_BACK && |
| (hasFullLevel || hasEnoughCapability)) { |
| // Found suitable camera - get info, open, and set up outputs |
| mCameraInfo = info; |
| openCamera(id); |
| foundCamera = true; |
| break; |
| } |
| } |
| if (!foundCamera) { |
| errorMessage = "no back camera"; |
| } |
| } catch (CameraAccessException e) { |
| errorMessage = e.getMessage(); |
| } |
| // startBackgroundThread |
| mBackgroundThread = new HandlerThread("CameraBackground"); |
| mBackgroundThread.start(); |
| mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); |
| return (foundCamera) ? null : errorMessage; |
| } |
| |
| |
| private boolean hasCapability(int[] capabilities, int capability) { |
| for (int c : capabilities) { |
| if (c == capability) return true; |
| } |
| return false; |
| } |
| |
| private final ImageReader.OnImageAvailableListener mOnImageAvailableListener |
| = new ImageReader.OnImageAvailableListener() { |
| |
| @Override |
| public void onImageAvailable(ImageReader reader) { |
| mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), |
| mSaveFileName, mContext,mCaptureMode)); |
| } |
| |
| }; |
| |
| /** |
| * Saves a JPEG {@link android.media.Image} into the specified {@link java.io.File}. |
| */ |
| private static class ImageSaver implements Runnable { |
| private final Image mImage; |
| private final String mName; |
| Context mContext; |
| private int mMode; |
| |
| public ImageSaver(Image image, String fileName, Context context,int mode) { |
| mImage = image; |
| mName = fileName; |
| mContext = context; |
| mMode = mode; |
| } |
| |
| @Override |
| public void run() { |
| Log.v(TAG, "S>> SAVING..."); |
| String url = MediaStoreSaver.insertImage(mContext.getContentResolver(), |
| new MediaStoreSaver.StreamWriter() { |
| @Override |
| public void write(OutputStream imageOut) throws IOException { |
| try { |
| ByteBuffer buffer = mImage.getPlanes()[0].getBuffer(); |
| byte[] bytes = new byte[buffer.remaining()]; |
| Log.v(TAG, "S>> size=" + mImage.getWidth() + |
| "," + mImage.getHeight()); |
| Log.v(TAG, "S>> bytes " + bytes.length + |
| " (" + bytes.length / (1024 * 1024) + "MB"); |
| Log.v(TAG, "S>> bytes out " + bytes.length / mImage.getWidth()); |
| buffer.get(bytes); |
| imageOut.write(bytes); |
| } finally { |
| mImage.close(); |
| } |
| } |
| }, mName, "Saved from Simple Camera Demo"); |
| ViewfinderProcessor.reProcessImage(mContext, url, mMode); |
| } |
| } |
| |
| /** |
| * Create a new camera ops thread. |
| * |
| * @param errorDisplayer listener for displaying error messages |
| * @param readyListener listener for notifying when camera is ready for requests |
| */ |
| CameraOps(CameraManager manager, ErrorDisplayer errorDisplayer, |
| CameraReadyListener readyListener) { |
| mReadyHandler = new Handler(Looper.getMainLooper()); |
| |
| mCameraThread = new HandlerThread("CameraOpsThread"); |
| mCameraThread.start(); |
| |
| if (manager == null || errorDisplayer == null || |
| readyListener == null || mReadyHandler == null) { |
| throw new IllegalArgumentException("Need valid displayer, listener, handler"); |
| } |
| |
| mCameraManager = manager; |
| mErrorDisplayer = errorDisplayer; |
| mReadyListener = readyListener; |
| |
| } |
| |
| /** |
| * Open the first backfacing camera listed by the camera manager. |
| * Displays a dialog if it cannot open a camera. |
| */ |
| public void openCamera(final String cameraId) { |
| mCameraHandler = new Handler(mCameraThread.getLooper()); |
| |
| mCameraHandler.post(new Runnable() { |
| public void run() { |
| if (mCameraDevice != null) { |
| throw new IllegalStateException("Camera already open"); |
| } |
| try { |
| |
| mCameraManager.openCamera(cameraId, mCameraDeviceListener, mCameraHandler); |
| } catch (CameraAccessException e) { |
| String errorMessage = mErrorDisplayer.getErrorString(e); |
| mErrorDisplayer.showErrorDialog(errorMessage); |
| } |
| } |
| }); |
| } |
| |
| public void pause() { |
| |
| closeCameraAndWait(); |
| mBackgroundThread.quitSafely(); |
| try { |
| mBackgroundThread.join(); |
| mBackgroundThread = null; |
| mBackgroundHandler = null; |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| public Size getBestSize() { |
| // Find a good size for output - largest 16:9 aspect ratio that's less than 720p |
| final int MAX_WIDTH = 640; |
| final float TARGET_ASPECT = 16.f / 9.f; |
| |
| |
| StreamConfigurationMap configs = |
| mCameraInfo.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); |
| |
| Size[] outputSizes = configs.getOutputSizes(SurfaceHolder.class); |
| |
| Size outputSize = null; |
| ArrayList<Size> smallEnough = new ArrayList<Size>(); |
| for (Size candidateSize : outputSizes) { |
| if (candidateSize.getWidth() <= MAX_WIDTH) { |
| Log.v(TAG, "consider " + candidateSize); |
| smallEnough.add(candidateSize); |
| } |
| } |
| if (smallEnough.size() == 0) { |
| return outputSizes[outputSizes.length - 1]; //pick the smallest |
| } |
| Size maxSize = smallEnough.get(0); |
| double aspectDelta = Math.abs(maxSize.getWidth() / maxSize.getHeight() - TARGET_ASPECT); |
| for (Size candidateSize : smallEnough) { |
| if (maxSize.getWidth() < candidateSize.getWidth()) { |
| maxSize = candidateSize; |
| aspectDelta = Math.abs(maxSize.getWidth() / maxSize.getHeight() - TARGET_ASPECT); |
| } |
| if (maxSize.getWidth() == candidateSize.getWidth()) { |
| if (aspectDelta > Math.abs(candidateSize.getWidth() / candidateSize.getHeight() - TARGET_ASPECT)) { |
| maxSize = candidateSize; |
| aspectDelta = Math.abs(maxSize.getWidth() / maxSize.getHeight() - TARGET_ASPECT); |
| } |
| } |
| } |
| |
| return maxSize; |
| } |
| |
| /** |
| * Close the camera and wait for the close callback to be called in the camera thread. |
| * Times out after @{value CAMERA_CLOSE_TIMEOUT} ms. |
| */ |
| public void closeCameraAndWait() { |
| mCloseWaiter.close(); |
| mCameraHandler.post(mCloseCameraRunnable); |
| boolean closed = mCloseWaiter.block(CAMERA_CLOSE_TIMEOUT); |
| if (!closed) { |
| Log.e(TAG, "Timeout closing camera"); |
| } |
| } |
| |
| private Runnable mCloseCameraRunnable = new Runnable() { |
| public void run() { |
| if (mCameraDevice != null) { |
| mCameraDevice.close(); |
| } |
| mCameraDevice = null; |
| mCameraSession = null; |
| mSurfaces = null; |
| } |
| }; |
| |
| /** |
| * Set the output Surfaces, and finish configuration if otherwise ready. |
| */ |
| public void setSurface(Surface surface) { |
| final List<Surface> surfaceList = new ArrayList<Surface>(); |
| surfaceList.add(surface); |
| surfaceList.add(mImageReader.getSurface()); |
| |
| mCameraHandler.post(new Runnable() { |
| public void run() { |
| mSurfaces = surfaceList; |
| startCameraSession(); |
| } |
| }); |
| } |
| |
| /** |
| * Get a request builder for the current camera. |
| */ |
| public CaptureRequest.Builder createCaptureRequest(int template) throws CameraAccessException { |
| CameraDevice device = mCameraDevice; |
| if (device == null) { |
| throw new IllegalStateException("Can't get requests when no camera is open"); |
| } |
| return device.createCaptureRequest(template); |
| } |
| |
| /** |
| * Set a repeating request. |
| */ |
| public void setRepeatingRequest(final CaptureRequest request, |
| final CameraCaptureSession.CaptureCallback listener, |
| final Handler handler) { |
| mCameraHandler.post(new Runnable() { |
| public void run() { |
| try { |
| mCameraSession.setRepeatingRequest(request, listener, handler); |
| } catch (CameraAccessException e) { |
| String errorMessage = mErrorDisplayer.getErrorString(e); |
| mErrorDisplayer.showErrorDialog(errorMessage); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Set a repeating request. |
| */ |
| public void setRepeatingBurst(final List<CaptureRequest> requests, |
| final CameraCaptureSession.CaptureCallback listener, |
| final Handler handler) { |
| mCameraHandler.post(new Runnable() { |
| public void run() { |
| try { |
| mCameraSession.setRepeatingBurst(requests, listener, handler); |
| |
| } catch (CameraAccessException e) { |
| String errorMessage = mErrorDisplayer.getErrorString(e); |
| mErrorDisplayer.showErrorDialog(errorMessage); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Configure the camera session. |
| */ |
| private void startCameraSession() { |
| // Wait until both the camera device is open and the SurfaceView is ready |
| if (mCameraDevice == null || mSurfaces == null) return; |
| |
| try { |
| |
| mCameraDevice.createCaptureSession( |
| mSurfaces, mCameraSessionListener, mCameraHandler); |
| } catch (CameraAccessException e) { |
| String errorMessage = mErrorDisplayer.getErrorString(e); |
| mErrorDisplayer.showErrorDialog(errorMessage); |
| mCameraDevice.close(); |
| mCameraDevice = null; |
| } |
| } |
| |
| /** |
| * Main listener for camera session events |
| * Invoked on mCameraThread |
| */ |
| private CameraCaptureSession.StateCallback mCameraSessionListener = |
| new CameraCaptureSession.StateCallback() { |
| |
| @Override |
| public void onConfigured(CameraCaptureSession session) { |
| mCameraSession = session; |
| mReadyHandler.post(new Runnable() { |
| public void run() { |
| // This can happen when the screen is turned off and turned back on. |
| if (null == mCameraDevice) { |
| return; |
| } |
| |
| mReadyListener.onCameraReady(); |
| } |
| }); |
| |
| } |
| |
| @Override |
| public void onConfigureFailed(CameraCaptureSession session) { |
| mErrorDisplayer.showErrorDialog("Unable to configure the capture session"); |
| mCameraDevice.close(); |
| mCameraDevice = null; |
| } |
| }; |
| |
| /** |
| * Main listener for camera device events. |
| * Invoked on mCameraThread |
| */ |
| private CameraDevice.StateCallback mCameraDeviceListener = new CameraDevice.StateCallback() { |
| |
| @Override |
| public void onOpened(CameraDevice camera) { |
| mCameraDevice = camera; |
| startCameraSession(); |
| } |
| |
| @Override |
| public void onClosed(CameraDevice camera) { |
| mCloseWaiter.open(); |
| } |
| |
| @Override |
| public void onDisconnected(CameraDevice camera) { |
| mErrorDisplayer.showErrorDialog("The camera device has been disconnected."); |
| camera.close(); |
| mCameraDevice = null; |
| } |
| |
| @Override |
| public void onError(CameraDevice camera, int error) { |
| mErrorDisplayer.showErrorDialog("The camera encountered an error:" + error); |
| camera.close(); |
| mCameraDevice = null; |
| } |
| |
| }; |
| |
| public void captureStillPicture(int currentJpegRotation, String name, Context context, int mode) { |
| mSaveFileName = name; |
| mContext = context; |
| mCaptureMode = mode; |
| try { |
| // TODO call lock focus if we are in "AF-S(One-Shot AF) mode" |
| // TODO call precapture if we are using flash |
| // This is the CaptureRequest.Builder that we use to take a picture. |
| final CaptureRequest.Builder captureBuilder = |
| createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); |
| Log.v(TAG, "S>> Target " + mImageReader.getWidth() + "," + mImageReader.getHeight()); |
| |
| captureBuilder.addTarget(mImageReader.getSurface()); |
| |
| captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, currentJpegRotation); |
| |
| CameraCaptureSession.CaptureCallback captureCallback |
| = new CameraCaptureSession.CaptureCallback() { |
| |
| @Override |
| public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, |
| TotalCaptureResult result) { |
| Log.v(TAG, "S>> onCaptureCompleted"); |
| setParameters(); |
| } |
| }; |
| |
| |
| setRequest(captureBuilder.build(), captureCallback, null); |
| } catch (CameraAccessException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| /** |
| * Set a repeating request. |
| */ |
| private void setRequest(final CaptureRequest request, |
| final CameraCaptureSession.CaptureCallback listener, |
| final Handler handler) { |
| mCameraHandler.post(new Runnable() { |
| public void run() { |
| try { |
| mCameraSession.stopRepeating(); |
| mCameraSession.capture(request, listener, handler); |
| } catch (CameraAccessException e) { |
| String errorMessage = mErrorDisplayer.getErrorString(e); |
| mErrorDisplayer.showErrorDialog(errorMessage); |
| } |
| } |
| }); |
| } |
| |
| public void setUpCamera(Surface processingNormalSurface) { |
| mProcessingNormalSurface = processingNormalSurface; |
| // Ready to send requests in, so set them up |
| try { |
| CaptureRequest.Builder previewBuilder = |
| createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); |
| previewBuilder.addTarget(mProcessingNormalSurface); |
| previewBuilder.setTag(mAutoExposureTag); |
| mPreviewRequest = previewBuilder.build(); |
| mHdrBuilder = createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); |
| mHdrBuilder.set(CaptureRequest.CONTROL_AE_MODE, |
| CaptureRequest.CONTROL_AE_MODE_OFF); |
| mHdrBuilder.addTarget(mProcessingNormalSurface); |
| setParameters(); |
| |
| } catch (CameraAccessException e) { |
| String errorMessage = e.getMessage(); |
| // MessageDialogFragment.newInstance(errorMessage).show(getFragmentManager(), FRAGMENT_DIALOG); |
| } |
| } |
| |
| /** |
| * Start running an HDR burst on a configured camera session |
| */ |
| public void setParameters() { |
| if (mHdrBuilder == null) { |
| Log.v(TAG, " Camera not set up"); |
| return; |
| } |
| if (mAutoExposure) { |
| mHdrBuilder.set(CaptureRequest.SENSOR_FRAME_DURATION, ONE_SECOND / 30); |
| mHdrBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, getExposure()); |
| mHdrBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); |
| } else { |
| mHdrBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF); |
| mHdrBuilder.set(CaptureRequest.SENSOR_FRAME_DURATION, ONE_SECOND / 30); |
| mHdrBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, getExposure()); |
| mHdrBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, getIso()); |
| } |
| if (mAutoFocus) { |
| mHdrBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO); |
| mHdrBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START); |
| } else { |
| mHdrBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF); |
| mHdrBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, getFocusDistance()); |
| mHdrBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START); |
| } |
| |
| setRepeatingRequest(mHdrBuilder.build(), mCaptureCallback, mReadyHandler); |
| } |
| |
| private CameraCaptureSession.CaptureCallback mCaptureCallback |
| = new CameraCaptureSession.CaptureCallback() { |
| |
| public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, |
| TotalCaptureResult result) { |
| } |
| }; |
| |
| /** |
| * Simple listener for main code to know the camera is ready for requests, or failed to |
| * start. |
| */ |
| public interface CameraReadyListener { |
| public void onCameraReady(); |
| } |
| |
| /** |
| * Simple listener for displaying error messages |
| */ |
| public interface ErrorDisplayer { |
| public void showErrorDialog(String errorMessage); |
| |
| public String getErrorString(CameraAccessException e); |
| } |
| |
| public float getFocusDistance() { |
| return mFocusDist; |
| } |
| |
| public void setFocusDistance(float focusDistance) { |
| mFocusDist = focusDistance; |
| } |
| |
| public void setIso(int iso) { |
| mIso = iso; |
| } |
| |
| public boolean isAutoExposure() { |
| return mAutoExposure; |
| } |
| |
| public void setAutoExposure(boolean autoExposure) { |
| mAutoExposure = autoExposure; |
| } |
| |
| public boolean isAutoFocus() { |
| return mAutoFocus; |
| } |
| |
| public void setAutoFocus(boolean autoFocus) { |
| mAutoFocus = autoFocus; |
| } |
| |
| public int getIso() { |
| return mIso; |
| } |
| |
| public long getExposure() { |
| return mExposure; |
| } |
| |
| public void setExposure(long exposure) { |
| mExposure = exposure; |
| } |
| |
| public int getIsoMax() { |
| return mISOmax; |
| } |
| |
| public int getIsoMin() { |
| return mISOmin; |
| } |
| |
| public long getExpMax() { |
| return mExpMax; |
| } |
| |
| public long getExpMin() { |
| return mExpMin; |
| } |
| |
| public float getFocusMin() { |
| return mFocusMin; |
| } |
| } |