title: camera2 pictures taken are blurred
body: <p>I'm experiencing a bad behavior when capturing a photo on a Samsung Galaxy S7 edge device.</p>
  
  <p>I wait simultaneously for focus and exposure before taking the picture but at the end I have a kind of blurred image compared to the native camera app output.</p>
  
  <p>The problem is especially visible on zoomed images but is present also when not zoomed. I've also tried to enable the optical image stabilization but the problem isn't fixed.</p>
  
  <p>Below are linked sample images explaining the problem.</p>
  
  <p><a href="http://i.stack.imgur.com/guQED.jpg" rel="nofollow">Native camera image</a></p>
  
  <p><a href="http://i.stack.imgur.com/1mbPq.jpg" rel="nofollow">My camera image</a></p>
  
  <p>Here is the code:</p>
  
  <p>Method for picture capture step 1:</p>
  
  <pre><code>public void capturePicture() {
      CameraState state = getState();
      if (state != IDLE &amp;&amp; state != CLOSING &amp;&amp; state != TAKE_PICTURE) {
              boolean af = false;
              boolean ae = false;
              if (isAFEnabled()) {
                  af = true;
              } else if (isAEEnabled()) {
                  ae = true;
              }
  
              if (!af &amp;&amp; !ae) {
                  takePicture();
              } else {
                  triggerFocusAndExposure(true);
              }
      }
  
      return;
  }
  </code></pre>
  
  <p>Method for triggering focus and exposure:</p>
  
  <pre><code>private void triggerFocusAndExposure(boolean picture) {
      setState(WAIT_PRECAPTURE_PICTURE);
  
      if (isAFEnabled()) {
          previewBuilder.set(CONTROL_AF_TRIGGER, CONTROL_AF_TRIGGER_START);
      }
  
      if (isAEEnabled()) {
          previewBuilder.set(CONTROL_AE_PRECAPTURE_TRIGGER, CONTROL_AE_PRECAPTURE_TRIGGER_START);
      }
  
      try {
          cameraSession.capture(previewBuilder.build(), new SCameraCaptureSession.CaptureCallback() {
              @Override public void onCaptureCompleted(SCameraCaptureSession session, SCaptureRequest request, STotalCaptureResult result) {
                  setState(PRECAPTURE_TRIGGERED_PICTURE);
              }
          }, backgroundHandler);
      } catch (CameraAccessException e) {
          return;
      }
  
      try {
          previewBuilder.set(CONTROL_AF_TRIGGER, CONTROL_AF_TRIGGER_IDLE);
          previewBuilder.set(CONTROL_AE_PRECAPTURE_TRIGGER, CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
          cameraSession.setRepeatingRequest(previewBuilder.build(), mSessionCaptureCallback, backgroundHandler);
      } catch (CameraAccessException e) {
      }
  }
  </code></pre>
  
  <p>Methods for waiting focus and exposure:</p>
  
  <pre><code>private void waitPrecapture(STotalCaptureResult result, boolean picture) {
      // Check if AF/AE triggered and/or finished
      if ((!isAFTriggered(result) || isAfFinished(result)) &amp;&amp; (!isAETriggered(result) || isAEFinished(result))) {
          takePicture();
      }
  }
  
  private boolean isAFTriggered(STotalCaptureResult result) {
      Integer afMode = result.get(SCaptureResult.CONTROL_AF_MODE);
      return afMode != CONTROL_AF_MODE_OFF &amp;&amp;
              afMode != CONTROL_AF_MODE_EDOF;
  }
  
  private boolean isAfFinished(STotalCaptureResult result) {
      int afState = result.get(SCaptureResult.CONTROL_AF_STATE);
      return afState == CONTROL_AF_STATE_FOCUSED_LOCKED || afState == CONTROL_AF_STATE_NOT_FOCUSED_LOCKED
              || afState == CONTROL_AF_STATE_PASSIVE_FOCUSED || afState == CONTROL_AF_STATE_PASSIVE_UNFOCUSED;
  }
  
  private boolean isAETriggered(STotalCaptureResult result) {
      boolean aeMode = result.get(SCaptureResult.CONTROL_AE_MODE) != SCaptureResult.CONTROL_AE_MODE_OFF;
      return aeMode &amp;&amp; cameraCharacteristics.get(SCameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL)
              != SCameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
  }
  
  private boolean isAEFinished(STotalCaptureResult result) {
      Integer aeState = result.get(SCaptureResult.CONTROL_AE_STATE);
      return aeState == null || aeState == SCaptureResult.CONTROL_AE_STATE_CONVERGED || aeState == SCaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED
              || aeState == SCaptureResult.CONTROL_AE_STATE_LOCKED;
  }
  </code></pre>
  
  <p>Method for picture capture step 2:</p>
  
  <pre><code>public void takePicture(){
      imageReader.setOnImageAvailableListener(reader -&gt; {
          Image image = reader.acquireLatestImage();
          ByteBuffer buffer = image.getPlanes()[0].getBuffer();
          byte[] bytes = new byte[buffer.remaining()];
          buffer.get(bytes);
          image.close();
          singleSubscriber.onSuccess(bytes);
      }, imageSavingHandler);
  
      try {
          cameraSession.capture(captureBuilder.build(), new SCameraCaptureSession.CaptureCallback() {
               @Override
               public void onCaptureCompleted(SCameraCaptureSession session, SCaptureRequest request, STotalCaptureResult result) {
                   if (getState() == CameraState.CLOSING) {
                       return;
                   }
                   cancelAF();
               }
  
               @Override
               public void onCaptureStarted(SCameraCaptureSession session, SCaptureRequest request, long timestamp, long frameNumber) {
                   super.onCaptureStarted(session, request, timestamp, frameNumber);
                   shutterCallback.call();
               }    
  
               @Override public void onCaptureFailed(SCameraCaptureSession session, SCaptureRequest request, SCaptureFailure failure) {
                    singleSubscriber.onError(new RuntimeException("Error taking picture, onCaptureFailed"));
                    if (getState() == CameraState.CLOSING) {
                        return;
                    }
                    cancelAF();
               }
           }, backgroundHandler);
  
           setState(CameraState.TAKE_PICTURE);
       } catch (CameraAccessException e) {
           singleSubscriber.onError(new RuntimeException("Error capturing image", e));
       }
  }
  </code></pre>