OSDN Git Service

Read focus range from CameraCharacteristics.
authorPaul Rohde <codelogic@google.com>
Thu, 12 Feb 2015 17:29:38 +0000 (09:29 -0800)
committerPaul Rohde <codelogic@google.com>
Thu, 12 Feb 2015 18:39:44 +0000 (10:39 -0800)
- Remove hardcoded focus range values.
- Explicitly provide a lens range and range checks.

Bug: 19356651

Change-Id: Ied2513b5a654a00af07e76a66e72aac50ffc9c42

13 files changed:
src/com/android/camera/one/OneCamera.java
src/com/android/camera/one/OneCameraCharacteristics.java
src/com/android/camera/one/v1/OneCameraCharacteristicsImpl.java
src/com/android/camera/one/v2/OneCameraCharacteristicsImpl.java
src/com/android/camera/one/v2/OneCameraImpl.java
src/com/android/camera/one/v2/OneCameraZslImpl.java
src/com/android/camera/one/v2/SimpleOneCameraFactory.java
src/com/android/camera/one/v2/ZslOneCameraFactory.java
src/com/android/camera/one/v2/initialization/GenericOneCameraImpl.java
src/com/android/camera/one/v2/initialization/InitializedOneCameraFactory.java
src/com/android/camera/ui/focus/FocusController.java
src/com/android/camera/ui/focus/LensRangeCalculator.java [new file with mode: 0644]
src/com/android/camera/ui/motion/LinearScale.java

index 49fb2c0..4593248 100644 (file)
@@ -26,6 +26,7 @@ import com.android.camera.burst.BurstConfiguration;
 import com.android.camera.burst.ResultsAccessor;
 import com.android.camera.session.CaptureSession;
 import com.android.camera.settings.SettingsManager;
+import com.android.camera.ui.motion.LinearScale;
 import com.android.camera.util.Size;
 
 import java.io.File;
@@ -212,27 +213,24 @@ public interface OneCamera {
     public static interface FocusDistanceListener {
         /**
          * Called when physical lens distance on the camera changes.
-         *
-         * @param diopter the lens diopter from the last known position.
-         * @param isActive whether the lens is moving.
          */
-        public void onFocusDistance(float diopter, boolean isActive);
+        public void onFocusDistance(float distance, LinearScale lensRange);
     }
 
     /**
      * Single instance of the current camera AF state.
      */
     public static class FocusState {
-        public final float diopter;
+        public final float lensDistance;
         public final boolean isActive;
 
         /**
-         * @param diopter The current focal distance.
+         * @param lensDistance The current focal distance.
          * @param isActive Whether the lens is moving, e.g. because of either an
          *            "active scan" or a "passive scan".
          */
-        public FocusState(float diopter, boolean isActive) {
-            this.diopter = diopter;
+        public FocusState(float lensDistance, boolean isActive) {
+            this.lensDistance = lensDistance;
             this.isActive = isActive;
         }
 
@@ -245,7 +243,7 @@ public interface OneCamera {
 
             FocusState that = (FocusState) o;
 
-            if (Float.compare(that.diopter, diopter) != 0)
+            if (Float.compare(that.lensDistance, lensDistance) != 0)
                 return false;
             if (isActive != that.isActive)
                 return false;
@@ -255,7 +253,7 @@ public interface OneCamera {
 
         @Override
         public int hashCode() {
-            int result = (diopter != +0.0f ? Float.floatToIntBits(diopter) : 0);
+            int result = (lensDistance != +0.0f ? Float.floatToIntBits(lensDistance) : 0);
             result = 31 * result + (isActive ? 1 : 0);
             return result;
         }
index 095ad17..2e17f51 100644 (file)
@@ -20,6 +20,7 @@ import android.graphics.ImageFormat;
 import android.graphics.Rect;
 import android.hardware.camera2.CameraCharacteristics;
 
+import com.android.camera.ui.motion.LinearScale;
 import com.android.camera.util.Size;
 
 import java.util.List;
@@ -75,4 +76,9 @@ public interface OneCameraCharacteristics {
      * @return The supported hardware level.
      */
     public SupportedHardwareLevel getSupportedHardwareLevel();
+
+    /**
+     * A converter from the physical focus range of the camera to a ratio.
+     */
+    public LinearScale getLensFocusRange();
 }
index 150b394..6470168 100644 (file)
@@ -21,6 +21,8 @@ import android.hardware.Camera;
 
 import com.android.camera.one.OneCamera;
 import com.android.camera.one.OneCameraCharacteristics;
+import com.android.camera.ui.focus.LensRangeCalculator;
+import com.android.camera.ui.motion.LinearScale;
 import com.android.camera.util.Size;
 
 import java.util.ArrayList;
@@ -103,4 +105,10 @@ public class OneCameraCharacteristicsImpl implements OneCameraCharacteristics {
     public SupportedHardwareLevel getSupportedHardwareLevel() {
         throw new RuntimeException("Not implemented yet.");
     }
+
+    @Override
+    public LinearScale getLensFocusRange() {
+        // Diopter range is not supported on legacy camera devices.
+        return LensRangeCalculator.getNoOp();
+    }
 }
index 77fcb11..866aa7c 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.android.camera.one.v2;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
 import android.hardware.camera2.CameraCharacteristics;
@@ -23,13 +25,13 @@ import android.hardware.camera2.params.StreamConfigurationMap;
 
 import com.android.camera.one.OneCamera;
 import com.android.camera.one.OneCameraCharacteristics;
+import com.android.camera.ui.focus.LensRangeCalculator;
+import com.android.camera.ui.motion.LinearScale;
 import com.android.camera.util.Size;
 
 import java.util.ArrayList;
 import java.util.List;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
 /**
  * Describes a OneCamera device which is on top of camera2 API. This is
  * essential a wrapper for #{link
@@ -111,4 +113,10 @@ public class OneCameraCharacteristicsImpl implements OneCameraCharacteristics {
                 throw new IllegalStateException("Invalid value for INFO_SUPPORTED_HARDWARE_LEVEL");
         }
     }
+
+    @Override
+    public LinearScale getLensFocusRange() {
+        return LensRangeCalculator
+              .getDiopterToRatioCalculator(mCameraCharacteristics);
+    }
 }
index 453c14e..c371eca 100644 (file)
@@ -57,6 +57,8 @@ import com.android.camera.one.OneCamera;
 import com.android.camera.one.Settings3A;
 import com.android.camera.one.v2.camera2proxy.AndroidImageProxy;
 import com.android.camera.session.CaptureSession;
+import com.android.camera.ui.focus.LensRangeCalculator;
+import com.android.camera.ui.motion.LinearScale;
 import com.android.camera.util.CameraUtil;
 import com.android.camera.util.CaptureDataSerializer;
 import com.android.camera.util.JpegUtilNative;
@@ -226,7 +228,7 @@ public class OneCameraImpl extends AbstractOneCamera {
 
                     Float diopter = result.get(CaptureResult.LENS_FOCUS_DISTANCE);
                     if(diopter != null && mFocusDistanceListener != null) {
-                        mFocusDistanceListener.onFocusDistance(diopter, true);
+                        mFocusDistanceListener.onFocusDistance(diopter, mLensRange);
                     }
 
                     if (request.getTag() == RequestTag.CAPTURE) {
@@ -253,6 +255,7 @@ public class OneCameraImpl extends AbstractOneCamera {
     private final Handler mCameraHandler;
     /** The characteristics of this camera. */
     private final CameraCharacteristics mCharacteristics;
+    private final LinearScale mLensRange;
     /** The underlying Camera2 API camera device. */
     private final CameraDevice mDevice;
     private final CameraDirectionProvider mDirectionProvider;
@@ -307,6 +310,7 @@ public class OneCameraImpl extends AbstractOneCamera {
     OneCameraImpl(CameraDevice device, CameraCharacteristics characteristics, Size pictureSize) {
         mDevice = device;
         mCharacteristics = characteristics;
+        mLensRange = LensRangeCalculator.getDiopterToRatioCalculator(characteristics);
         mDirectionProvider = new CameraDirectionProvider(characteristics);
         mFullSizeAspectRatio = calculateFullSizeAspectRatio(characteristics);
 
index 0a57aec..b81dfaa 100644 (file)
@@ -60,6 +60,8 @@ import com.android.camera.one.v2.ImageCaptureManager.ImageCaptureListener;
 import com.android.camera.one.v2.ImageCaptureManager.MetadataChangeListener;
 import com.android.camera.one.v2.camera2proxy.AndroidImageProxy;
 import com.android.camera.session.CaptureSession;
+import com.android.camera.ui.focus.LensRangeCalculator;
+import com.android.camera.ui.motion.LinearScale;
 import com.android.camera.util.CameraUtil;
 import com.android.camera.util.JpegUtilNative;
 import com.android.camera.util.ListenerCombiner;
@@ -148,6 +150,8 @@ public class OneCameraZslImpl extends AbstractOneCamera {
 
     /** The characteristics of this camera. */
     private final CameraCharacteristics mCharacteristics;
+    /** Converts focus distance units into ratio values */
+    private final LinearScale mLensRange;
     /** The underlying Camera2 API camera device. */
     private final CameraDevice mDevice;
     private final CameraDirectionProvider mDirection;
@@ -292,6 +296,8 @@ public class OneCameraZslImpl extends AbstractOneCamera {
 
         mDevice = device;
         mCharacteristics = characteristics;
+        mLensRange = LensRangeCalculator
+              .getDiopterToRatioCalculator(characteristics);
         mDirection = new CameraDirectionProvider(mCharacteristics);
         mFullSizeAspectRatio = calculateFullSizeAspectRatio(characteristics);
 
@@ -364,10 +370,13 @@ public class OneCameraZslImpl extends AbstractOneCamera {
                             Object newValue,
                             CaptureResult result) {
                           Integer state = result.get(CaptureResult.LENS_STATE);
-                          if (newValue != null && state != null) {
-                              mFocusDistanceListener.onFocusDistance((float) newValue, state == 1);
-                          } else if (newValue != null) {
-                              mFocusDistanceListener.onFocusDistance((float) newValue, true);
+
+                          // Forward changes if we have a new value and the camera
+                          // A) Doesn't support lens state or B) lens state is
+                          // reported and it is reported as moving.
+                          if (newValue != null &&
+                                (state == null || state == CameraMetadata.LENS_STATE_MOVING)) {
+                              mFocusDistanceListener.onFocusDistance((float) newValue, mLensRange);
                           }
                       }
                   });
index 9cf6192..e688cda 100644 (file)
@@ -223,7 +223,8 @@ public class SimpleOneCameraFactory implements OneCameraFactory {
         OneCamera.Facing direction = characteristics.getCameraDirection();
 
         return new InitializedOneCameraFactory(lifetime, cameraStarter, device, outputSurfaces,
-                mainExecutor, new HandlerFactory(), maxZoom, supportedPreviewSizes, direction)
+                mainExecutor, new HandlerFactory(), maxZoom, supportedPreviewSizes,
+                characteristics.getLensFocusRange(), direction)
                 .provideOneCamera();
     }
 }
index 3c13f77..e576d33 100644 (file)
@@ -229,6 +229,7 @@ public class ZslOneCameraFactory implements OneCameraFactory {
         OneCamera.Facing direction = characteristics.getCameraDirection();
         return new InitializedOneCameraFactory(lifetime, cameraStarter, device,
                 outputSurfaces, mainThread, new HandlerFactory(), maxZoom,
-                supportedPreviewSizes, direction).provideOneCamera();
+                supportedPreviewSizes, characteristics.getLensFocusRange(),
+                direction).provideOneCamera();
     }
 }
index 32c2cb1..43d6129 100644 (file)
@@ -19,7 +19,6 @@ package com.android.camera.one.v2.initialization;
 import android.content.Context;
 import android.view.Surface;
 
-import com.android.camera.async.ConcurrentState;
 import com.android.camera.async.Listenable;
 import com.android.camera.async.SafeCloseable;
 import com.android.camera.async.Updatable;
@@ -28,6 +27,7 @@ import com.android.camera.one.v2.AutoFocusHelper;
 import com.android.camera.one.v2.autofocus.ManualAutoFocus;
 import com.android.camera.one.v2.photo.PictureTaker;
 import com.android.camera.session.CaptureSession;
+import com.android.camera.ui.motion.LinearScale;
 import com.android.camera.util.Callback;
 import com.android.camera.util.Size;
 import com.google.common.util.concurrent.FutureCallback;
@@ -35,7 +35,6 @@ import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 
 import java.util.concurrent.Executor;
-import java.util.concurrent.Future;
 
 import javax.annotation.Nonnull;
 
@@ -54,6 +53,7 @@ class GenericOneCameraImpl implements OneCamera {
     private final SafeCloseable mCloseListener;
     private final PictureTaker mPictureTaker;
     private final ManualAutoFocus mManualAutoFocus;
+    private final LinearScale mLensRange;
     private final Executor mMainExecutor;
     private final Listenable<Integer> mAFStateListenable;
     private final Listenable<FocusState> mFocusStateListenable;
@@ -65,7 +65,7 @@ class GenericOneCameraImpl implements OneCamera {
     private final PreviewStarter mPreviewStarter;
 
     public GenericOneCameraImpl(SafeCloseable closeListener, PictureTaker pictureTaker,
-            ManualAutoFocus manualAutoFocus, Executor mainExecutor,
+            ManualAutoFocus manualAutoFocus, LinearScale lensRange, Executor mainExecutor,
             Listenable<Integer> afStateProvider, Listenable<FocusState> focusStateProvider,
             Listenable<Boolean> readyStateListenable, float maxZoom, Updatable<Float> zoom,
             Facing direction, PreviewSizeSelector previewSizeSelector,
@@ -77,6 +77,7 @@ class GenericOneCameraImpl implements OneCamera {
         mPreviewSizeSelector = previewSizeSelector;
         mPictureTaker = pictureTaker;
         mManualAutoFocus = manualAutoFocus;
+        mLensRange = lensRange;
         mAFStateListenable = afStateProvider;
         mFocusStateListenable = focusStateProvider;
         mReadyStateListenable = readyStateListenable;
@@ -108,7 +109,7 @@ class GenericOneCameraImpl implements OneCamera {
     public void setFocusStateListener(final FocusStateListener listener) {
         mAFStateListenable.setCallback(new Callback<Integer>() {
             @Override
-            public void onCallback(Integer afState) {
+            public void onCallback(@Nonnull Integer afState) {
                 // TODO delete frameNumber from FocusStateListener callback. It
                 // is optional and never actually used.
                 long frameNumber = -1;
@@ -122,8 +123,10 @@ class GenericOneCameraImpl implements OneCamera {
     public void setFocusDistanceListener(final FocusDistanceListener listener) {
         mFocusStateListenable.setCallback(new Callback<FocusState>() {
             @Override
-            public void onCallback(FocusState focusState) {
-                listener.onFocusDistance(focusState.diopter, focusState.isActive);
+            public void onCallback(@Nonnull FocusState focusState) {
+                if (focusState.isActive) {
+                    listener.onFocusDistance(focusState.lensDistance, mLensRange);
+                }
             }
         });
     }
index c54fb6d..7d4ac12 100644 (file)
@@ -33,6 +33,7 @@ import com.android.camera.one.v2.autofocus.ManualAutoFocus;
 import com.android.camera.one.v2.camera2proxy.CameraCaptureSessionProxy;
 import com.android.camera.one.v2.camera2proxy.CameraDeviceProxy;
 import com.android.camera.one.v2.photo.PictureTaker;
+import com.android.camera.ui.motion.LinearScale;
 import com.android.camera.util.Size;
 import com.google.common.util.concurrent.SettableFuture;
 
@@ -73,7 +74,7 @@ public class InitializedOneCameraFactory {
             final Lifetime lifetime, final CameraStarter cameraStarter, CameraDeviceProxy device,
             List<Surface> outputSurfaces, Executor mainThreadExecutor,
             HandlerFactory handlerFactory, float maxZoom, List<Size> supportedPreviewSizes,
-            OneCamera.Facing direction) {
+            LinearScale lensRange, OneCamera.Facing direction) {
         // Assembles and returns a OneCamera based on the CameraStarter.
 
         // Create/wrap required threads.
@@ -151,7 +152,7 @@ public class InitializedOneCameraFactory {
 
         PreviewSizeSelector previewSizeSelector = new PreviewSizeSelector(supportedPreviewSizes);
 
-        mOneCamera = new GenericOneCameraImpl(lifetime, pictureTaker, manualAutoFocus,
+        mOneCamera = new GenericOneCameraImpl(lifetime, pictureTaker, manualAutoFocus, lensRange,
                 mainThreadExecutor, afStateListenable, focusStateListenable, readyStateListenable,
                 maxZoom, zoomState, direction, previewSizeSelector, mPreviewStarter);
     }
index 3ffd1db..ad5e6fe 100644 (file)
@@ -28,22 +28,15 @@ import com.android.camera.ui.motion.LinearScale;
  */
 public class FocusController implements FocusDistanceListener {
     private static final Tag TAG = new Tag("FocusController");
-    // A Diopter of 0.0f ish is infinity.
-    // A Diopter of about 15f or so is focused "as close as possible"
-    // Diopter max is computed from device testing
-    private static final float DIOPTER_MIN = 0.0f;
-    private static final float DIOPTER_MAX = 15.0f;
 
     private final FocusRing mFocusRing;
     private final FocusSound mFocusSound;
     private final MainThread mMainThread;
-    private final LinearScale mDiopterToRatio;
 
     public FocusController(FocusRing focusRing, FocusSound focusSound, MainThread mainThread) {
         mFocusRing = focusRing;
         mFocusSound = focusSound;
         mMainThread = mainThread;
-        mDiopterToRatio = new LinearScale(DIOPTER_MIN, DIOPTER_MAX, 0, 1);
     }
 
     /**
@@ -127,7 +120,8 @@ public class FocusController implements FocusDistanceListener {
     }
 
     /**
-     * Set the physical radius of the focus ring in pixels.
+     * Set the radius of the focus ring as a radius between 0 and 1.
+     * This will map to the min and max values computed for the UI.
      */
     public void setFocusRatio(final float ratio) {
         mMainThread.execute(new Runnable() {
@@ -142,15 +136,9 @@ public class FocusController implements FocusDistanceListener {
     }
 
     @Override
-    public void onFocusDistance(final float diopter, final boolean isActive) {
-        mMainThread.execute(new Runnable() {
-            @Override
-            public void run() {
-                if (isActive || mFocusRing.isPassiveFocusRunning() ||
-                    mFocusRing.isActiveFocusRunning()) {
-                    mFocusRing.setRadiusRatio(mDiopterToRatio.scale(diopter));
-                }
-            }
-        });
+    public void onFocusDistance(float lensDistance, LinearScale lensRange) {
+        if (lensRange.isInDomain(lensDistance)) {
+            setFocusRatio(lensRange.scale(lensDistance));
+        }
     }
 }
diff --git a/src/com/android/camera/ui/focus/LensRangeCalculator.java b/src/com/android/camera/ui/focus/LensRangeCalculator.java
new file mode 100644 (file)
index 0000000..5e9f5c4
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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.camera.ui.focus;
+
+import android.annotation.TargetApi;
+import android.hardware.camera2.CameraCharacteristics;
+import android.os.Build.VERSION_CODES;
+
+import com.android.camera.debug.Log;
+import com.android.camera.debug.Log.Tag;
+import com.android.camera.ui.motion.LinearScale;
+
+/**
+ * Compute diopter range scale to convert lens focus distances into
+ * a ratio value.
+ */
+@TargetApi(VERSION_CODES.L)
+public class LensRangeCalculator {
+
+    /**
+     * A NoOp linear scale for computing diopter values will always return 0
+     */
+    public static LinearScale getNoOp() {
+        return new LinearScale(0, 0, 0, 0);
+    }
+
+    /**
+     * Compute the focus range from the camera characteristics and build
+     * a linear scale model that maps a focus distance to a ratio between
+     * the min and max range.
+     */
+    public static LinearScale getDiopterToRatioCalculator(CameraCharacteristics characteristics) {
+        // From the android documentation:
+        // 0.0f represents farthest focus, and LENS_INFO_MINIMUM_FOCUS_DISTANCE
+        // represents the nearest focus the device can achieve.
+        Float nearest = characteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
+        Float hyperfocal = characteristics.get(CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE);
+
+        if (nearest == null && hyperfocal == null) {
+            return getNoOp();
+        }
+
+        nearest = (nearest == null) ? 0.0f : nearest;
+        hyperfocal = (hyperfocal == null) ? 0.0f : hyperfocal;
+
+        if (nearest > hyperfocal) {
+            return new LinearScale(hyperfocal, nearest, 0, 1);
+        }
+
+        return new LinearScale(nearest, hyperfocal, 0, 1);
+    }
+}
index 2c7284c..53cdcd4 100644 (file)
@@ -49,6 +49,16 @@ public final class LinearScale {
     }
 
     /**
+     * Returns true if the value is within the domain.
+     */
+    public boolean isInDomain(float domainValue) {
+        if (mDomainA > mDomainB) {
+            return domainValue >= mDomainA && domainValue <= mDomainB;
+        }
+        return domainValue >= mDomainB && domainValue <= mDomainA;
+    }
+
+    /**
      * Linearly scale a given domain value into the output range.
      */
     public float scale(float domainValue) {