content: /*
   * Copyright (C) 2012 ZXing authors
   *
   * 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.
   *
   * -- Class modifications
   *
   * Copyright 2016 David Lázaro Esparcia.
   *
   * 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.alipay.hulu.ui.scan.camera;
  
  import android.hardware.Camera;
  import android.os.AsyncTask;
  import android.util.Log;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.concurrent.RejectedExecutionException;
  
  final class AutoFocusManager implements Camera.AutoFocusCallback {
  
      private static final String TAG = AutoFocusManager.class.getSimpleName();
  
      protected static final long DEFAULT_AUTO_FOCUS_INTERVAL_MS = 5000L;
      private static final Collection<String> FOCUS_MODES_CALLING_AF;
      private long autofocusIntervalMs = DEFAULT_AUTO_FOCUS_INTERVAL_MS;
  
      static {
          FOCUS_MODES_CALLING_AF = new ArrayList<>(2);
          FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_AUTO);
          FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_MACRO);
      }
  
      private boolean stopped;
      private boolean focusing;
      private final boolean useAutoFocus;
      private final Camera camera;
      private AsyncTask<?, ?, ?> outstandingTask;
  
      AutoFocusManager(Camera camera) {
          this.camera = camera;
          String currentFocusMode = camera.getParameters().getFocusMode();
          useAutoFocus = FOCUS_MODES_CALLING_AF.contains(currentFocusMode);
          Log.i(TAG, "Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus);
          start();
      }
  
      @Override public synchronized void onAutoFocus(boolean success, Camera theCamera) {
          focusing = false;
          autoFocusAgainLater();
      }
  
      public void setAutofocusInterval(long autofocusIntervalMs) {
          if (autofocusIntervalMs <= 0) {
              throw new IllegalArgumentException("AutoFocusInterval must be greater than 0.");
          }
          this.autofocusIntervalMs = autofocusIntervalMs;
      }
  
      private synchronized void autoFocusAgainLater() {
          if (!stopped && outstandingTask == null) {
              AutoFocusTask newTask = new AutoFocusTask();
              try {
                  newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
                  outstandingTask = newTask;
              } catch (RejectedExecutionException ree) {
                  Log.w(TAG, "Could not request auto focus", ree);
              }
          }
      }
  
      synchronized void start() {
          if (useAutoFocus) {
              outstandingTask = null;
              if (!stopped && !focusing) {
                  try {
                      camera.autoFocus(this);
                      focusing = true;
                  } catch (RuntimeException re) {
                      // Have heard RuntimeException reported in Android 4.0.x+; continue?
                      Log.w(TAG, "Unexpected exception while focusing", re);
                      // Try again later to keep cycle going
                      autoFocusAgainLater();
                  }
              }
          }
      }
  
      private synchronized void cancelOutstandingTask() {
          if (outstandingTask != null) {
              if (outstandingTask.getStatus() != AsyncTask.Status.FINISHED) {
                  outstandingTask.cancel(true);
              }
              outstandingTask = null;
          }
      }
  
      synchronized void stop() {
          stopped = true;
          if (useAutoFocus) {
              cancelOutstandingTask();
              // Doesn't hurt to call this even if not focusing
              try {
                  camera.cancelAutoFocus();
              } catch (RuntimeException re) {
                  // Have heard RuntimeException reported in Android 4.0.x+; continue?
                  Log.w(TAG, "Unexpected exception while cancelling focusing", re);
              }
          }
      }
  
      private final class AutoFocusTask extends AsyncTask<Object, Object, Object> {
          @Override protected Object doInBackground(Object... voids) {
              try {
                  Thread.sleep(autofocusIntervalMs);
              } catch (InterruptedException e) {
                  // continue
              }
              start();
              return null;
          }
      }
  }