1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.example.cannylive; 18 19 import android.content.Context; 20 import android.graphics.ImageFormat; 21 import android.hardware.camera2.CameraAccessException; 22 import android.hardware.camera2.CameraCaptureSession; 23 import android.hardware.camera2.CameraCharacteristics; 24 import android.hardware.camera2.CameraDevice; 25 import android.hardware.camera2.CameraManager; 26 import android.hardware.camera2.CaptureRequest; 27 import android.hardware.camera2.TotalCaptureResult; 28 import android.hardware.camera2.params.StreamConfigurationMap; 29 import android.media.Image; 30 import android.media.ImageReader; 31 import android.os.ConditionVariable; 32 import android.os.Handler; 33 import android.os.HandlerThread; 34 import android.os.Looper; 35 import android.util.Log; 36 import android.util.Range; 37 import android.util.Size; 38 import android.view.Surface; 39 import android.view.SurfaceHolder; 40 41 import java.io.IOException; 42 import java.io.OutputStream; 43 import java.nio.ByteBuffer; 44 import java.util.ArrayList; 45 import java.util.Arrays; 46 import java.util.Collections; 47 import java.util.Comparator; 48 import java.util.List; 49 50 /** 51 * Simple interface for operating the camera, with major camera operations 52 * all performed on a background handler thread. 53 */ 54 public class CameraOps { 55 56 private static final String TAG = "CameraOps"; 57 private static final long ONE_SECOND = 1000000000; 58 public static final long CAMERA_CLOSE_TIMEOUT = 2000; // ms 59 60 private final CameraManager mCameraManager; 61 private CameraDevice mCameraDevice; 62 private CameraCaptureSession mCameraSession; 63 private List<Surface> mSurfaces; 64 65 private final ConditionVariable mCloseWaiter = new ConditionVariable(); 66 67 private HandlerThread mCameraThread; 68 private Handler mCameraHandler; 69 70 private final ErrorDisplayer mErrorDisplayer; 71 72 private final CameraReadyListener mReadyListener; 73 private final Handler mReadyHandler; 74 75 private int mISOmax; 76 private int mISOmin; 77 private long mExpMax; 78 private long mExpMin; 79 private float mFocusMin; 80 private float mFocusDist = 0; 81 private int mIso; 82 boolean mAutoExposure = true; 83 boolean mAutoFocus = true; 84 private long mExposure = ONE_SECOND / 33; 85 86 private Object mAutoExposureTag = new Object(); 87 88 private ImageReader mImageReader; 89 private Handler mBackgroundHandler; 90 private CameraCharacteristics mCameraInfo; 91 private HandlerThread mBackgroundThread; 92 CaptureRequest.Builder mHdrBuilder; 93 private Surface mProcessingNormalSurface; 94 CaptureRequest mPreviewRequest; 95 private String mSaveFileName; 96 private Context mContext; 97 private int mCaptureMode; 98 resume()99 public String resume() { 100 String errorMessage = "Unknown error"; 101 boolean foundCamera = false; 102 try { 103 // Find first back-facing camera that has necessary capability 104 String[] cameraIds = mCameraManager.getCameraIdList(); 105 for (String id : cameraIds) { 106 CameraCharacteristics info = mCameraManager.getCameraCharacteristics(id); 107 int facing = info.get(CameraCharacteristics.LENS_FACING); 108 109 int level = info.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 110 boolean hasFullLevel 111 = (level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL); 112 113 int[] capabilities = info.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 114 int syncLatency = info.get(CameraCharacteristics.SYNC_MAX_LATENCY); 115 boolean hasManualControl = hasCapability(capabilities, 116 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR); 117 boolean hasEnoughCapability = hasManualControl && 118 syncLatency == CameraCharacteristics.SYNC_MAX_LATENCY_PER_FRAME_CONTROL; 119 Range<Integer> irange; 120 Range<Long> lrange; 121 122 irange = info.get(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE); 123 if (irange != null) { 124 mISOmax = irange.getUpper(); 125 mISOmin = irange.getLower(); 126 lrange = info.get(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE); 127 mExpMax = lrange.getUpper(); 128 mExpMin = lrange.getLower(); 129 mFocusMin = info.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE); 130 } else { 131 mISOmax = 200; 132 mISOmin = 100; 133 mExpMax = 1000; 134 } 135 mFocusDist = mFocusMin; 136 StreamConfigurationMap map = info.get( 137 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 138 Size[] sizes = map.getOutputSizes(ImageFormat.JPEG); 139 List<Size> sizeList = Arrays.asList(sizes); 140 Collections.sort(sizeList, new Comparator<Size>() { 141 @Override 142 public int compare(Size lhs, Size rhs) { 143 int leftArea = lhs.getHeight() * lhs.getWidth(); 144 int rightArea = lhs.getHeight() * lhs.getWidth(); 145 return Integer.compare(leftArea, rightArea); 146 } 147 }); 148 Size max = sizeList.get(0); 149 int check = 1; 150 Size big = sizeList.get(check); 151 float aspect = 16/9f; 152 Log.v(TAG,"max big "+max.getWidth()+" x "+max.getHeight()); 153 for (int i = 0; i < sizeList.size(); i++) { 154 Size s = sizeList.get(i); 155 if (s.getHeight() == 720) { 156 big = s; 157 break; 158 } 159 } 160 Log.v(TAG,"BIG wil be "+big.getWidth()+" x "+big.getHeight()); 161 mImageReader = ImageReader.newInstance(big.getWidth(), big.getHeight(), 162 ImageFormat.JPEG, /*maxImages*/2); 163 mImageReader.setOnImageAvailableListener( 164 mOnImageAvailableListener, mBackgroundHandler); 165 166 if (facing == CameraCharacteristics.LENS_FACING_BACK && 167 (hasFullLevel || hasEnoughCapability)) { 168 // Found suitable camera - get info, open, and set up outputs 169 mCameraInfo = info; 170 openCamera(id); 171 foundCamera = true; 172 break; 173 } 174 } 175 if (!foundCamera) { 176 errorMessage = "no back camera"; 177 } 178 } catch (CameraAccessException e) { 179 errorMessage = e.getMessage(); 180 } 181 // startBackgroundThread 182 mBackgroundThread = new HandlerThread("CameraBackground"); 183 mBackgroundThread.start(); 184 mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); 185 return (foundCamera) ? null : errorMessage; 186 } 187 188 hasCapability(int[] capabilities, int capability)189 private boolean hasCapability(int[] capabilities, int capability) { 190 for (int c : capabilities) { 191 if (c == capability) return true; 192 } 193 return false; 194 } 195 196 private final ImageReader.OnImageAvailableListener mOnImageAvailableListener 197 = new ImageReader.OnImageAvailableListener() { 198 199 @Override 200 public void onImageAvailable(ImageReader reader) { 201 mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), 202 mSaveFileName, mContext,mCaptureMode)); 203 } 204 205 }; 206 207 /** 208 * Saves a JPEG {@link android.media.Image} into the specified {@link java.io.File}. 209 */ 210 private static class ImageSaver implements Runnable { 211 private final Image mImage; 212 private final String mName; 213 Context mContext; 214 private int mMode; 215 ImageSaver(Image image, String fileName, Context context,int mode)216 public ImageSaver(Image image, String fileName, Context context,int mode) { 217 mImage = image; 218 mName = fileName; 219 mContext = context; 220 mMode = mode; 221 } 222 223 @Override run()224 public void run() { 225 Log.v(TAG, "S>> SAVING..."); 226 String url = MediaStoreSaver.insertImage(mContext.getContentResolver(), 227 new MediaStoreSaver.StreamWriter() { 228 @Override 229 public void write(OutputStream imageOut) throws IOException { 230 try { 231 ByteBuffer buffer = mImage.getPlanes()[0].getBuffer(); 232 byte[] bytes = new byte[buffer.remaining()]; 233 Log.v(TAG, "S>> size=" + mImage.getWidth() + 234 "," + mImage.getHeight()); 235 Log.v(TAG, "S>> bytes " + bytes.length + 236 " (" + bytes.length / (1024 * 1024) + "MB"); 237 Log.v(TAG, "S>> bytes out " + bytes.length / mImage.getWidth()); 238 buffer.get(bytes); 239 imageOut.write(bytes); 240 } finally { 241 mImage.close(); 242 } 243 } 244 }, mName, "Saved from Simple Camera Demo"); 245 ViewfinderProcessor.reProcessImage(mContext, url, mMode); 246 } 247 } 248 249 /** 250 * Create a new camera ops thread. 251 * 252 * @param errorDisplayer listener for displaying error messages 253 * @param readyListener listener for notifying when camera is ready for requests 254 */ CameraOps(CameraManager manager, ErrorDisplayer errorDisplayer, CameraReadyListener readyListener)255 CameraOps(CameraManager manager, ErrorDisplayer errorDisplayer, 256 CameraReadyListener readyListener) { 257 mReadyHandler = new Handler(Looper.getMainLooper()); 258 259 mCameraThread = new HandlerThread("CameraOpsThread"); 260 mCameraThread.start(); 261 262 if (manager == null || errorDisplayer == null || 263 readyListener == null || mReadyHandler == null) { 264 throw new IllegalArgumentException("Need valid displayer, listener, handler"); 265 } 266 267 mCameraManager = manager; 268 mErrorDisplayer = errorDisplayer; 269 mReadyListener = readyListener; 270 271 } 272 273 /** 274 * Open the first backfacing camera listed by the camera manager. 275 * Displays a dialog if it cannot open a camera. 276 */ openCamera(final String cameraId)277 public void openCamera(final String cameraId) { 278 mCameraHandler = new Handler(mCameraThread.getLooper()); 279 280 mCameraHandler.post(new Runnable() { 281 public void run() { 282 if (mCameraDevice != null) { 283 throw new IllegalStateException("Camera already open"); 284 } 285 try { 286 287 mCameraManager.openCamera(cameraId, mCameraDeviceListener, mCameraHandler); 288 } catch (CameraAccessException e) { 289 String errorMessage = mErrorDisplayer.getErrorString(e); 290 mErrorDisplayer.showErrorDialog(errorMessage); 291 } 292 } 293 }); 294 } 295 pause()296 public void pause() { 297 298 closeCameraAndWait(); 299 mBackgroundThread.quitSafely(); 300 try { 301 mBackgroundThread.join(); 302 mBackgroundThread = null; 303 mBackgroundHandler = null; 304 } catch (InterruptedException e) { 305 e.printStackTrace(); 306 } 307 } 308 getBestSize()309 public Size getBestSize() { 310 // Find a good size for output - largest 16:9 aspect ratio that's less than 720p 311 final int MAX_WIDTH = 640; 312 final float TARGET_ASPECT = 16.f / 9.f; 313 314 315 StreamConfigurationMap configs = 316 mCameraInfo.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 317 318 Size[] outputSizes = configs.getOutputSizes(SurfaceHolder.class); 319 320 Size outputSize = null; 321 ArrayList<Size> smallEnough = new ArrayList<Size>(); 322 for (Size candidateSize : outputSizes) { 323 if (candidateSize.getWidth() <= MAX_WIDTH) { 324 Log.v(TAG, "consider " + candidateSize); 325 smallEnough.add(candidateSize); 326 } 327 } 328 if (smallEnough.size() == 0) { 329 return outputSizes[outputSizes.length - 1]; //pick the smallest 330 } 331 Size maxSize = smallEnough.get(0); 332 double aspectDelta = Math.abs(maxSize.getWidth() / maxSize.getHeight() - TARGET_ASPECT); 333 for (Size candidateSize : smallEnough) { 334 if (maxSize.getWidth() < candidateSize.getWidth()) { 335 maxSize = candidateSize; 336 aspectDelta = Math.abs(maxSize.getWidth() / maxSize.getHeight() - TARGET_ASPECT); 337 } 338 if (maxSize.getWidth() == candidateSize.getWidth()) { 339 if (aspectDelta > Math.abs(candidateSize.getWidth() / candidateSize.getHeight() - TARGET_ASPECT)) { 340 maxSize = candidateSize; 341 aspectDelta = Math.abs(maxSize.getWidth() / maxSize.getHeight() - TARGET_ASPECT); 342 } 343 } 344 } 345 346 return maxSize; 347 } 348 349 /** 350 * Close the camera and wait for the close callback to be called in the camera thread. 351 * Times out after @{value CAMERA_CLOSE_TIMEOUT} ms. 352 */ closeCameraAndWait()353 public void closeCameraAndWait() { 354 mCloseWaiter.close(); 355 mCameraHandler.post(mCloseCameraRunnable); 356 boolean closed = mCloseWaiter.block(CAMERA_CLOSE_TIMEOUT); 357 if (!closed) { 358 Log.e(TAG, "Timeout closing camera"); 359 } 360 } 361 362 private Runnable mCloseCameraRunnable = new Runnable() { 363 public void run() { 364 if (mCameraDevice != null) { 365 mCameraDevice.close(); 366 } 367 mCameraDevice = null; 368 mCameraSession = null; 369 mSurfaces = null; 370 } 371 }; 372 373 /** 374 * Set the output Surfaces, and finish configuration if otherwise ready. 375 */ setSurface(Surface surface)376 public void setSurface(Surface surface) { 377 final List<Surface> surfaceList = new ArrayList<Surface>(); 378 surfaceList.add(surface); 379 surfaceList.add(mImageReader.getSurface()); 380 381 mCameraHandler.post(new Runnable() { 382 public void run() { 383 mSurfaces = surfaceList; 384 startCameraSession(); 385 } 386 }); 387 } 388 389 /** 390 * Get a request builder for the current camera. 391 */ createCaptureRequest(int template)392 public CaptureRequest.Builder createCaptureRequest(int template) throws CameraAccessException { 393 CameraDevice device = mCameraDevice; 394 if (device == null) { 395 throw new IllegalStateException("Can't get requests when no camera is open"); 396 } 397 return device.createCaptureRequest(template); 398 } 399 400 /** 401 * Set a repeating request. 402 */ setRepeatingRequest(final CaptureRequest request, final CameraCaptureSession.CaptureCallback listener, final Handler handler)403 public void setRepeatingRequest(final CaptureRequest request, 404 final CameraCaptureSession.CaptureCallback listener, 405 final Handler handler) { 406 mCameraHandler.post(new Runnable() { 407 public void run() { 408 try { 409 mCameraSession.setRepeatingRequest(request, listener, handler); 410 } catch (CameraAccessException e) { 411 String errorMessage = mErrorDisplayer.getErrorString(e); 412 mErrorDisplayer.showErrorDialog(errorMessage); 413 } 414 } 415 }); 416 } 417 418 /** 419 * Set a repeating request. 420 */ setRepeatingBurst(final List<CaptureRequest> requests, final CameraCaptureSession.CaptureCallback listener, final Handler handler)421 public void setRepeatingBurst(final List<CaptureRequest> requests, 422 final CameraCaptureSession.CaptureCallback listener, 423 final Handler handler) { 424 mCameraHandler.post(new Runnable() { 425 public void run() { 426 try { 427 mCameraSession.setRepeatingBurst(requests, listener, handler); 428 429 } catch (CameraAccessException e) { 430 String errorMessage = mErrorDisplayer.getErrorString(e); 431 mErrorDisplayer.showErrorDialog(errorMessage); 432 } 433 } 434 }); 435 } 436 437 /** 438 * Configure the camera session. 439 */ startCameraSession()440 private void startCameraSession() { 441 // Wait until both the camera device is open and the SurfaceView is ready 442 if (mCameraDevice == null || mSurfaces == null) return; 443 444 try { 445 446 mCameraDevice.createCaptureSession( 447 mSurfaces, mCameraSessionListener, mCameraHandler); 448 } catch (CameraAccessException e) { 449 String errorMessage = mErrorDisplayer.getErrorString(e); 450 mErrorDisplayer.showErrorDialog(errorMessage); 451 mCameraDevice.close(); 452 mCameraDevice = null; 453 } 454 } 455 456 /** 457 * Main listener for camera session events 458 * Invoked on mCameraThread 459 */ 460 private CameraCaptureSession.StateCallback mCameraSessionListener = 461 new CameraCaptureSession.StateCallback() { 462 463 @Override 464 public void onConfigured(CameraCaptureSession session) { 465 mCameraSession = session; 466 mReadyHandler.post(new Runnable() { 467 public void run() { 468 // This can happen when the screen is turned off and turned back on. 469 if (null == mCameraDevice) { 470 return; 471 } 472 473 mReadyListener.onCameraReady(); 474 } 475 }); 476 477 } 478 479 @Override 480 public void onConfigureFailed(CameraCaptureSession session) { 481 mErrorDisplayer.showErrorDialog("Unable to configure the capture session"); 482 mCameraDevice.close(); 483 mCameraDevice = null; 484 } 485 }; 486 487 /** 488 * Main listener for camera device events. 489 * Invoked on mCameraThread 490 */ 491 private CameraDevice.StateCallback mCameraDeviceListener = new CameraDevice.StateCallback() { 492 493 @Override 494 public void onOpened(CameraDevice camera) { 495 mCameraDevice = camera; 496 startCameraSession(); 497 } 498 499 @Override 500 public void onClosed(CameraDevice camera) { 501 mCloseWaiter.open(); 502 } 503 504 @Override 505 public void onDisconnected(CameraDevice camera) { 506 mErrorDisplayer.showErrorDialog("The camera device has been disconnected."); 507 camera.close(); 508 mCameraDevice = null; 509 } 510 511 @Override 512 public void onError(CameraDevice camera, int error) { 513 mErrorDisplayer.showErrorDialog("The camera encountered an error:" + error); 514 camera.close(); 515 mCameraDevice = null; 516 } 517 518 }; 519 captureStillPicture(int currentJpegRotation, String name, Context context, int mode)520 public void captureStillPicture(int currentJpegRotation, String name, Context context, int mode) { 521 mSaveFileName = name; 522 mContext = context; 523 mCaptureMode = mode; 524 try { 525 // TODO call lock focus if we are in "AF-S(One-Shot AF) mode" 526 // TODO call precapture if we are using flash 527 // This is the CaptureRequest.Builder that we use to take a picture. 528 final CaptureRequest.Builder captureBuilder = 529 createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 530 Log.v(TAG, "S>> Target " + mImageReader.getWidth() + "," + mImageReader.getHeight()); 531 532 captureBuilder.addTarget(mImageReader.getSurface()); 533 534 captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, currentJpegRotation); 535 536 CameraCaptureSession.CaptureCallback captureCallback 537 = new CameraCaptureSession.CaptureCallback() { 538 539 @Override 540 public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, 541 TotalCaptureResult result) { 542 Log.v(TAG, "S>> onCaptureCompleted"); 543 setParameters(); 544 } 545 }; 546 547 548 setRequest(captureBuilder.build(), captureCallback, null); 549 } catch (CameraAccessException e) { 550 e.printStackTrace(); 551 } 552 } 553 554 /** 555 * Set a repeating request. 556 */ setRequest(final CaptureRequest request, final CameraCaptureSession.CaptureCallback listener, final Handler handler)557 private void setRequest(final CaptureRequest request, 558 final CameraCaptureSession.CaptureCallback listener, 559 final Handler handler) { 560 mCameraHandler.post(new Runnable() { 561 public void run() { 562 try { 563 mCameraSession.stopRepeating(); 564 mCameraSession.capture(request, listener, handler); 565 } catch (CameraAccessException e) { 566 String errorMessage = mErrorDisplayer.getErrorString(e); 567 mErrorDisplayer.showErrorDialog(errorMessage); 568 } 569 } 570 }); 571 } 572 setUpCamera(Surface processingNormalSurface)573 public void setUpCamera(Surface processingNormalSurface) { 574 mProcessingNormalSurface = processingNormalSurface; 575 // Ready to send requests in, so set them up 576 try { 577 CaptureRequest.Builder previewBuilder = 578 createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 579 previewBuilder.addTarget(mProcessingNormalSurface); 580 previewBuilder.setTag(mAutoExposureTag); 581 mPreviewRequest = previewBuilder.build(); 582 mHdrBuilder = createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 583 mHdrBuilder.set(CaptureRequest.CONTROL_AE_MODE, 584 CaptureRequest.CONTROL_AE_MODE_OFF); 585 mHdrBuilder.addTarget(mProcessingNormalSurface); 586 setParameters(); 587 588 } catch (CameraAccessException e) { 589 String errorMessage = e.getMessage(); 590 // MessageDialogFragment.newInstance(errorMessage).show(getFragmentManager(), FRAGMENT_DIALOG); 591 } 592 } 593 594 /** 595 * Start running an HDR burst on a configured camera session 596 */ setParameters()597 public void setParameters() { 598 if (mHdrBuilder == null) { 599 Log.v(TAG, " Camera not set up"); 600 return; 601 } 602 if (mAutoExposure) { 603 mHdrBuilder.set(CaptureRequest.SENSOR_FRAME_DURATION, ONE_SECOND / 30); 604 mHdrBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, getExposure()); 605 mHdrBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); 606 } else { 607 mHdrBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF); 608 mHdrBuilder.set(CaptureRequest.SENSOR_FRAME_DURATION, ONE_SECOND / 30); 609 mHdrBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, getExposure()); 610 mHdrBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, getIso()); 611 } 612 if (mAutoFocus) { 613 mHdrBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO); 614 mHdrBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START); 615 } else { 616 mHdrBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF); 617 mHdrBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, getFocusDistance()); 618 mHdrBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START); 619 } 620 621 setRepeatingRequest(mHdrBuilder.build(), mCaptureCallback, mReadyHandler); 622 } 623 624 private CameraCaptureSession.CaptureCallback mCaptureCallback 625 = new CameraCaptureSession.CaptureCallback() { 626 627 public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, 628 TotalCaptureResult result) { 629 } 630 }; 631 632 /** 633 * Simple listener for main code to know the camera is ready for requests, or failed to 634 * start. 635 */ 636 public interface CameraReadyListener { onCameraReady()637 public void onCameraReady(); 638 } 639 640 /** 641 * Simple listener for displaying error messages 642 */ 643 public interface ErrorDisplayer { showErrorDialog(String errorMessage)644 public void showErrorDialog(String errorMessage); 645 getErrorString(CameraAccessException e)646 public String getErrorString(CameraAccessException e); 647 } 648 getFocusDistance()649 public float getFocusDistance() { 650 return mFocusDist; 651 } 652 setFocusDistance(float focusDistance)653 public void setFocusDistance(float focusDistance) { 654 mFocusDist = focusDistance; 655 } 656 setIso(int iso)657 public void setIso(int iso) { 658 mIso = iso; 659 } 660 isAutoExposure()661 public boolean isAutoExposure() { 662 return mAutoExposure; 663 } 664 setAutoExposure(boolean autoExposure)665 public void setAutoExposure(boolean autoExposure) { 666 mAutoExposure = autoExposure; 667 } 668 isAutoFocus()669 public boolean isAutoFocus() { 670 return mAutoFocus; 671 } 672 setAutoFocus(boolean autoFocus)673 public void setAutoFocus(boolean autoFocus) { 674 mAutoFocus = autoFocus; 675 } 676 getIso()677 public int getIso() { 678 return mIso; 679 } 680 getExposure()681 public long getExposure() { 682 return mExposure; 683 } 684 setExposure(long exposure)685 public void setExposure(long exposure) { 686 mExposure = exposure; 687 } 688 getIsoMax()689 public int getIsoMax() { 690 return mISOmax; 691 } 692 getIsoMin()693 public int getIsoMin() { 694 return mISOmin; 695 } 696 getExpMax()697 public long getExpMax() { 698 return mExpMax; 699 } 700 getExpMin()701 public long getExpMin() { 702 return mExpMin; 703 } 704 getFocusMin()705 public float getFocusMin() { 706 return mFocusMin; 707 } 708 } 709