diff --git a/fotoapparat/src/main/java/io/fotoapparat/Fotoapparat.java b/fotoapparat/src/main/java/io/fotoapparat/Fotoapparat.java index a52772cb..c29e4d02 100644 --- a/fotoapparat/src/main/java/io/fotoapparat/Fotoapparat.java +++ b/fotoapparat/src/main/java/io/fotoapparat/Fotoapparat.java @@ -1,6 +1,7 @@ package io.fotoapparat; import android.content.Context; +import android.support.annotation.FloatRange; import android.support.annotation.NonNull; import java.util.concurrent.Executor; @@ -28,6 +29,7 @@ import io.fotoapparat.routine.focus.AutoFocusRoutine; import io.fotoapparat.routine.parameter.UpdateParametersRoutine; import io.fotoapparat.routine.picture.TakePictureRoutine; +import io.fotoapparat.routine.zoom.UpdateZoomLevelRoutine; /** * Camera. Takes pictures. @@ -45,6 +47,7 @@ public class Fotoapparat { private final AutoFocusRoutine autoFocusRoutine; private final CheckAvailabilityRoutine checkAvailabilityRoutine; private final UpdateParametersRoutine updateParametersRoutine; + private final UpdateZoomLevelRoutine updateZoomLevelRoutine; private final Executor executor; private boolean started = false; @@ -58,6 +61,7 @@ public class Fotoapparat { AutoFocusRoutine autoFocusRoutine, CheckAvailabilityRoutine checkAvailabilityRoutine, UpdateParametersRoutine updateParametersRoutine, + UpdateZoomLevelRoutine updateZoomLevelRoutine, Executor executor) { this.startCameraRoutine = startCameraRoutine; this.stopCameraRoutine = stopCameraRoutine; @@ -68,6 +72,7 @@ public class Fotoapparat { this.autoFocusRoutine = autoFocusRoutine; this.checkAvailabilityRoutine = checkAvailabilityRoutine; this.updateParametersRoutine = updateParametersRoutine; + this.updateZoomLevelRoutine = updateZoomLevelRoutine; this.executor = executor; } @@ -151,6 +156,10 @@ static Fotoapparat create(FotoapparatBuilder builder) { cameraDevice ); + UpdateZoomLevelRoutine updateZoomLevelRoutine = new UpdateZoomLevelRoutine( + cameraDevice + ); + return new Fotoapparat( startCameraRoutine, stopCameraRoutine, @@ -161,6 +170,7 @@ static Fotoapparat create(FotoapparatBuilder builder) { autoFocusRoutine, checkAvailabilityRoutine, updateParametersRoutine, + updateZoomLevelRoutine, SERIAL_EXECUTOR ); } @@ -216,8 +226,7 @@ public PendingResult focus() { } /** - * Asynchronously updates parameters of the camera. Must be called only after - * {@link Fotoapparat#start()}. + * Asynchronously updates parameters of the camera. Must be called only after {@link #start()}. */ public void updateParameters(@NonNull final UpdateRequest updateRequest) { ensureStarted(); @@ -230,6 +239,24 @@ public void run() { }); } + /** + * Asynchronously updates zoom level of the camera. Must be called only after {@link #start()}. + *

+ * If zoom is not supported by the device - does nothing. + * + * @param zoomLevel zoom level of the camera. A value between 0 and 1. + */ + public void setZoom(@FloatRange(from = 0f, to = 1f) final float zoomLevel) { + ensureStarted(); + + executor.execute(new Runnable() { + @Override + public void run() { + updateZoomLevelRoutine.updateZoomLevel(zoomLevel); + } + }); + } + /** * Starts camera. * diff --git a/fotoapparat/src/main/java/io/fotoapparat/hardware/CameraDevice.java b/fotoapparat/src/main/java/io/fotoapparat/hardware/CameraDevice.java index 0f68ce50..6593ea72 100644 --- a/fotoapparat/src/main/java/io/fotoapparat/hardware/CameraDevice.java +++ b/fotoapparat/src/main/java/io/fotoapparat/hardware/CameraDevice.java @@ -1,5 +1,7 @@ package io.fotoapparat.hardware; +import android.support.annotation.FloatRange; + import java.util.List; import io.fotoapparat.hardware.operators.AutoFocusOperator; @@ -13,13 +15,14 @@ import io.fotoapparat.hardware.operators.PreviewStreamOperator; import io.fotoapparat.hardware.operators.RendererParametersOperator; import io.fotoapparat.hardware.operators.SurfaceOperator; +import io.fotoapparat.hardware.operators.ZoomOperator; import io.fotoapparat.hardware.provider.AvailableLensPositionsProvider; +import io.fotoapparat.lens.FocusResult; import io.fotoapparat.parameter.LensPosition; import io.fotoapparat.parameter.Parameters; import io.fotoapparat.parameter.RendererParameters; import io.fotoapparat.photo.Photo; import io.fotoapparat.preview.PreviewStream; -import io.fotoapparat.lens.FocusResult; /** * Abstraction for camera hardware. @@ -27,7 +30,8 @@ public interface CameraDevice extends CaptureOperator, PreviewOperator, CapabilitiesOperator, OrientationOperator, ParametersOperator, ConnectionOperator, SurfaceOperator, PreviewStreamOperator, RendererParametersOperator, - ExposureMeasurementOperator, AutoFocusOperator, AvailableLensPositionsProvider { + ExposureMeasurementOperator, AutoFocusOperator, AvailableLensPositionsProvider, + ZoomOperator { @Override void open(LensPosition lensPosition); @@ -71,4 +75,7 @@ public interface CameraDevice extends CaptureOperator, @Override List getAvailableLensPositions(); + @Override + void setZoom(@FloatRange(from = 0f, to = 1f) float level); + } diff --git a/fotoapparat/src/main/java/io/fotoapparat/hardware/Capabilities.java b/fotoapparat/src/main/java/io/fotoapparat/hardware/Capabilities.java index 125f305c..eed38ad2 100644 --- a/fotoapparat/src/main/java/io/fotoapparat/hardware/Capabilities.java +++ b/fotoapparat/src/main/java/io/fotoapparat/hardware/Capabilities.java @@ -22,15 +22,18 @@ public class Capabilities { private final Set focusModes; @NonNull private final Set flashModes; + private final boolean zoomSupported; public Capabilities(@NonNull Set photoSizes, @NonNull Set previewSizes, @NonNull Set focusModes, - @NonNull Set flashModes) { + @NonNull Set flashModes, + boolean zoomSupported) { this.photoSizes = photoSizes; this.previewSizes = previewSizes; this.focusModes = focusModes; this.flashModes = flashModes; + this.zoomSupported = zoomSupported; } /** @@ -41,7 +44,8 @@ public static Capabilities empty() { Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), - Collections.emptySet() + Collections.emptySet(), + false ); } @@ -73,6 +77,13 @@ public Set supportedFlashModes() { return flashModes; } + /** + * @return {@code true} if zoom feature is supported. {@code false} if it is not supported. + */ + public boolean isZoomSupported() { + return zoomSupported; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -80,7 +91,8 @@ public boolean equals(Object o) { Capabilities that = (Capabilities) o; - return photoSizes.equals(that.photoSizes) + return zoomSupported == that.zoomSupported + && photoSizes.equals(that.photoSizes) && previewSizes.equals(that.previewSizes) && focusModes.equals(that.focusModes) && flashModes.equals(that.flashModes); @@ -93,6 +105,7 @@ public int hashCode() { result = 31 * result + previewSizes.hashCode(); result = 31 * result + focusModes.hashCode(); result = 31 * result + flashModes.hashCode(); + result = 31 * result + (zoomSupported ? 1 : 0); return result; } @@ -103,6 +116,7 @@ public String toString() { ", previewSizes=" + previewSizes + ", focusModes=" + focusModes + ", flashModes=" + flashModes + + ", zoomSupported=" + zoomSupported + '}'; } diff --git a/fotoapparat/src/main/java/io/fotoapparat/hardware/operators/ZoomOperator.java b/fotoapparat/src/main/java/io/fotoapparat/hardware/operators/ZoomOperator.java new file mode 100644 index 00000000..fb542729 --- /dev/null +++ b/fotoapparat/src/main/java/io/fotoapparat/hardware/operators/ZoomOperator.java @@ -0,0 +1,17 @@ +package io.fotoapparat.hardware.operators; + +import android.support.annotation.FloatRange; + +/** + * Modifies zoom level of the camera. + */ +public interface ZoomOperator { + + /** + * Changes zoom level of the camera. Must be called only if zoom is supported. + * + * @param level normalized zoom level. Value in range [0..1]. + */ + void setZoom(@FloatRange(from = 0f, to = 1f) float level); + +} diff --git a/fotoapparat/src/main/java/io/fotoapparat/hardware/v1/Camera1.java b/fotoapparat/src/main/java/io/fotoapparat/hardware/v1/Camera1.java index f73007d4..b6c629cf 100644 --- a/fotoapparat/src/main/java/io/fotoapparat/hardware/v1/Camera1.java +++ b/fotoapparat/src/main/java/io/fotoapparat/hardware/v1/Camera1.java @@ -1,7 +1,9 @@ package io.fotoapparat.hardware.v1; import android.hardware.Camera; +import android.support.annotation.FloatRange; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.view.SurfaceView; import android.view.TextureView; @@ -52,6 +54,11 @@ public class Camera1 implements CameraDevice { private Throwable lastStacktrace; private int imageRotation; + @Nullable + private Capabilities cachedCapabilities = null; + @Nullable + private Camera.Parameters cachedZoomParameters = null; + public Camera1(Logger logger) { this.capabilitiesFactory = new CapabilitiesFactory(); this.parametersConverter = new ParametersConverter(); @@ -123,6 +130,8 @@ private int facingForLensPosition(LensPosition lensPosition) { public void close() { recordMethod(); + cachedCapabilities = null; + if (isCameraOpened()) { camera.release(); } @@ -207,6 +216,8 @@ public void updateParameters(Parameters parameters) { recordMethod(); parametersOperator().updateParameters(parameters); + + cachedZoomParameters = null; } @NonNull @@ -231,11 +242,19 @@ private SwitchOnFailureParametersOperator parametersOperator() { @Override public Capabilities getCapabilities() { + if (cachedCapabilities != null) { + return cachedCapabilities; + } + recordMethod(); - return capabilitiesFactory.fromParameters( + Capabilities capabilities = capabilitiesFactory.fromParameters( camera.getParameters() ); + + cachedCapabilities = capabilities; + + return capabilities; } private void trySetDisplaySurface(Object displaySurface) throws IOException { @@ -353,6 +372,31 @@ public List getAvailableLensPositions() { return availableLensPositionsProvider.getAvailableLensPositions(); } + @Override + public void setZoom(@FloatRange(from = 0f, to = 1f) float level) { + try { + setZoomUnsafe(level); + } catch (Exception e) { + logFailedZoomUpdate(level, e); + } + } + + private void setZoomUnsafe(@FloatRange(from = 0f, to = 1f) float level) { + if (cachedZoomParameters == null) { + cachedZoomParameters = camera.getParameters(); + } + + cachedZoomParameters.setZoom( + (int) (cachedZoomParameters.getMaxZoom() * level) + ); + + camera.setParameters(cachedZoomParameters); + } + + private void logFailedZoomUpdate(float level, Exception e) { + logger.log("Unable to change zoom level to " + level + " e: " + e.getMessage()); + } + private Size previewSize() { Camera.Size previewSize = camera.getParameters().getPreviewSize(); diff --git a/fotoapparat/src/main/java/io/fotoapparat/hardware/v1/capabilities/CapabilitiesFactory.java b/fotoapparat/src/main/java/io/fotoapparat/hardware/v1/capabilities/CapabilitiesFactory.java index 6984a454..6c46b826 100644 --- a/fotoapparat/src/main/java/io/fotoapparat/hardware/v1/capabilities/CapabilitiesFactory.java +++ b/fotoapparat/src/main/java/io/fotoapparat/hardware/v1/capabilities/CapabilitiesFactory.java @@ -29,7 +29,8 @@ public Capabilities fromParameters(Camera.Parameters parameters) { extractPictureSizes(parameters), extractPreviewSizes(parameters), extractFocusModes(parameters), - extractFlashModes(parameters) + extractFlashModes(parameters), + parameters.isZoomSupported() ); } diff --git a/fotoapparat/src/main/java/io/fotoapparat/hardware/v2/Camera2.java b/fotoapparat/src/main/java/io/fotoapparat/hardware/v2/Camera2.java index 71bb64cd..fec05f9c 100644 --- a/fotoapparat/src/main/java/io/fotoapparat/hardware/v2/Camera2.java +++ b/fotoapparat/src/main/java/io/fotoapparat/hardware/v2/Camera2.java @@ -1,6 +1,7 @@ package io.fotoapparat.hardware.v2; import android.os.Build; +import android.support.annotation.FloatRange; import android.support.annotation.RequiresApi; import java.util.List; @@ -172,6 +173,11 @@ public List getAvailableLensPositions() { return availableLensPositionsProvider.getAvailableLensPositions(); } + @Override + public void setZoom(@FloatRange(from = 0f, to = 1f) float level) { + throw new UnsupportedOperationException("Not implemented. We do not actively support Camera2 at the moment."); + } + private void recordMethod() { Exception lastStacktrace = new Exception(); diff --git a/fotoapparat/src/main/java/io/fotoapparat/hardware/v2/capabilities/CapabilitiesFactory.java b/fotoapparat/src/main/java/io/fotoapparat/hardware/v2/capabilities/CapabilitiesFactory.java index 277745df..1a04d22d 100644 --- a/fotoapparat/src/main/java/io/fotoapparat/hardware/v2/capabilities/CapabilitiesFactory.java +++ b/fotoapparat/src/main/java/io/fotoapparat/hardware/v2/capabilities/CapabilitiesFactory.java @@ -35,7 +35,8 @@ public Capabilities getCapabilities() { availableJpegSizes(), availablePreviewSizes(), availableFocusModes(), - availableFlashModes() + availableFlashModes(), + false ); } diff --git a/fotoapparat/src/main/java/io/fotoapparat/routine/zoom/UpdateZoomLevelRoutine.java b/fotoapparat/src/main/java/io/fotoapparat/routine/zoom/UpdateZoomLevelRoutine.java new file mode 100644 index 00000000..db1d4057 --- /dev/null +++ b/fotoapparat/src/main/java/io/fotoapparat/routine/zoom/UpdateZoomLevelRoutine.java @@ -0,0 +1,48 @@ +package io.fotoapparat.routine.zoom; + +import android.support.annotation.FloatRange; + +import io.fotoapparat.hardware.CameraDevice; + +/** + * Updates zoom level of the camera. If zoom is not supported - does nothing. + */ +public class UpdateZoomLevelRoutine { + + private final CameraDevice cameraDevice; + + public UpdateZoomLevelRoutine(CameraDevice cameraDevice) { + this.cameraDevice = cameraDevice; + } + + /** + * Updates zoom level of the camera. If zoom is not supported - does nothing. + * + * @param zoomLevel zoom level of the camera. Value between 0 and 1. + */ + public void updateZoomLevel(@FloatRange(from = 0f, to = 1f) float zoomLevel) { + ensureInBounds(zoomLevel); + + if (cameraDevice.getCapabilities().isZoomSupported()) { + cameraDevice.setZoom(zoomLevel); + } + } + + private void ensureInBounds(float zoomLevel) { + if (zoomLevel < 0f || zoomLevel > 1f) { + throw new LevelOutOfRangeException(zoomLevel); + } + } + + /** + * Thrown when zoom level is outside of [0..1] range. + */ + static class LevelOutOfRangeException extends RuntimeException { + + public LevelOutOfRangeException(float zoomLevel) { + super(zoomLevel + " is out of range [0..1]"); + } + + } + +} diff --git a/fotoapparat/src/test/java/io/fotoapparat/FotoapparatTest.java b/fotoapparat/src/test/java/io/fotoapparat/FotoapparatTest.java index dbc62648..4b919b7b 100644 --- a/fotoapparat/src/test/java/io/fotoapparat/FotoapparatTest.java +++ b/fotoapparat/src/test/java/io/fotoapparat/FotoapparatTest.java @@ -23,6 +23,7 @@ import io.fotoapparat.routine.focus.AutoFocusRoutine; import io.fotoapparat.routine.parameter.UpdateParametersRoutine; import io.fotoapparat.routine.picture.TakePictureRoutine; +import io.fotoapparat.routine.zoom.UpdateZoomLevelRoutine; import io.fotoapparat.test.ImmediateExecutor; import static io.fotoapparat.test.TestUtils.immediateFuture; @@ -72,6 +73,8 @@ public class FotoapparatTest { CheckAvailabilityRoutine checkAvailabilityRoutine; @Mock UpdateParametersRoutine updateParametersRoutine; + @Mock + UpdateZoomLevelRoutine updateZoomLevelRoutine; Fotoapparat testee; @@ -87,6 +90,7 @@ public void setUp() throws Exception { autoFocusRoutine, checkAvailabilityRoutine, updateParametersRoutine, + updateZoomLevelRoutine, new ImmediateExecutor() ); } @@ -315,4 +319,25 @@ public void updateParameters_NotStartedYet() throws Exception { // Expect exception } + @Test + public void setZoom() throws Exception { + // Given + testee.start(); + + // When + testee.setZoom(0.5f); + + // Then + verify(updateZoomLevelRoutine).updateZoomLevel(0.5f); + } + + @Test(expected = IllegalStateException.class) + public void setZoom_NotStartedYet() throws Exception { + // When + testee.setZoom(1f); + + // Then + // Expect exception + } + } \ No newline at end of file diff --git a/fotoapparat/src/test/java/io/fotoapparat/hardware/v1/CapabilitiesFactoryTest.java b/fotoapparat/src/test/java/io/fotoapparat/hardware/v1/CapabilitiesFactoryTest.java index 7dd73739..35566b7c 100644 --- a/fotoapparat/src/test/java/io/fotoapparat/hardware/v1/CapabilitiesFactoryTest.java +++ b/fotoapparat/src/test/java/io/fotoapparat/hardware/v1/CapabilitiesFactoryTest.java @@ -21,6 +21,7 @@ import static java.util.Arrays.asList; import static java.util.Collections.singleton; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; import static org.mockito.BDDMockito.given; @RunWith(MockitoJUnitRunner.class) @@ -44,6 +45,8 @@ public void setUp() throws Exception { .willReturn(Collections.emptyList()); given(parameters.getSupportedPreviewSizes()) .willReturn(Collections.emptyList()); + given(parameters.isZoomSupported()) + .willReturn(false); testee = new CapabilitiesFactory(); } @@ -181,6 +184,19 @@ public void mapPreviewSizes() throws Exception { ); } + @Test + public void zoomSupported() throws Exception { + // Given + given(parameters.isZoomSupported()) + .willReturn(true); + + // When + Capabilities capabilities = testee.fromParameters(parameters); + + // Then + assertTrue(capabilities.isZoomSupported()); + } + @NonNull private Camera.Size makeSize(int width, int height) { Camera.Size size = camera.new Size(0, 0); diff --git a/fotoapparat/src/test/java/io/fotoapparat/hardware/v2/Camera2Test.java b/fotoapparat/src/test/java/io/fotoapparat/hardware/v2/Camera2Test.java index c956d0cb..84aee84a 100644 --- a/fotoapparat/src/test/java/io/fotoapparat/hardware/v2/Camera2Test.java +++ b/fotoapparat/src/test/java/io/fotoapparat/hardware/v2/Camera2Test.java @@ -156,7 +156,8 @@ public void getCapabilities() throws Exception { Collections.emptySet(), Collections.emptySet(), singleton(FocusMode.MACRO), - Collections.emptySet() + Collections.emptySet(), + false ); given(capabilitiesOperator.getCapabilities()) .willReturn(capabilities); diff --git a/fotoapparat/src/test/java/io/fotoapparat/parameter/factory/ParametersFactoryTest.java b/fotoapparat/src/test/java/io/fotoapparat/parameter/factory/ParametersFactoryTest.java index 7bf89d26..6f8d972b 100644 --- a/fotoapparat/src/test/java/io/fotoapparat/parameter/factory/ParametersFactoryTest.java +++ b/fotoapparat/src/test/java/io/fotoapparat/parameter/factory/ParametersFactoryTest.java @@ -2,8 +2,6 @@ import org.junit.Test; -import java.util.Collections; - import io.fotoapparat.hardware.Capabilities; import io.fotoapparat.parameter.Flash; import io.fotoapparat.parameter.FocusMode; @@ -15,14 +13,7 @@ public class ParametersFactoryTest { - static final Capabilities CAPABILITIES = new Capabilities( - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet() - ); - - final ParametersFactory testee = new ParametersFactory(); + static final Capabilities CAPABILITIES = Capabilities.empty(); @Test public void selectPictureSize() throws Exception { diff --git a/fotoapparat/src/test/java/io/fotoapparat/parameter/provider/InitialParametersProviderTest.java b/fotoapparat/src/test/java/io/fotoapparat/parameter/provider/InitialParametersProviderTest.java index 7d5e7aeb..eafc4fc0 100644 --- a/fotoapparat/src/test/java/io/fotoapparat/parameter/provider/InitialParametersProviderTest.java +++ b/fotoapparat/src/test/java/io/fotoapparat/parameter/provider/InitialParametersProviderTest.java @@ -85,7 +85,8 @@ public void initialParameters() throws Exception { asSet(PHOTO_SIZE), ALL_PREVIEW_SIZES, asSet(FocusMode.AUTO), - asSet(Flash.TORCH) + asSet(Flash.TORCH), + true )); InitialParametersProvider testee = new InitialParametersProvider( diff --git a/fotoapparat/src/test/java/io/fotoapparat/routine/parameter/UpdateParametersRoutineTest.java b/fotoapparat/src/test/java/io/fotoapparat/routine/parameter/UpdateParametersRoutineTest.java index d4689652..093f0d5e 100644 --- a/fotoapparat/src/test/java/io/fotoapparat/routine/parameter/UpdateParametersRoutineTest.java +++ b/fotoapparat/src/test/java/io/fotoapparat/routine/parameter/UpdateParametersRoutineTest.java @@ -39,7 +39,8 @@ public void setUp() throws Exception { Collections.emptySet(), Collections.emptySet(), asSet(FocusMode.AUTO), - asSet(Flash.TORCH) + asSet(Flash.TORCH), + false )); } diff --git a/fotoapparat/src/test/java/io/fotoapparat/routine/zoom/UpdateZoomLevelRoutineTest.java b/fotoapparat/src/test/java/io/fotoapparat/routine/zoom/UpdateZoomLevelRoutineTest.java new file mode 100644 index 00000000..edbf7844 --- /dev/null +++ b/fotoapparat/src/test/java/io/fotoapparat/routine/zoom/UpdateZoomLevelRoutineTest.java @@ -0,0 +1,95 @@ +package io.fotoapparat.routine.zoom; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Collections; + +import io.fotoapparat.hardware.CameraDevice; +import io.fotoapparat.hardware.Capabilities; +import io.fotoapparat.parameter.Flash; +import io.fotoapparat.parameter.FocusMode; +import io.fotoapparat.parameter.Size; +import io.fotoapparat.routine.zoom.UpdateZoomLevelRoutine.LevelOutOfRangeException; + +import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class UpdateZoomLevelRoutineTest { + + @Mock + CameraDevice cameraDevice; + + @InjectMocks + UpdateZoomLevelRoutine testee; + + @SuppressWarnings("Range") + @Test(expected = LevelOutOfRangeException.class) + public void outOfRange_Higher() throws Exception { + // When + testee.updateZoomLevel(1.1f); + + // Then + // Expect exception + } + + @SuppressWarnings("Range") + @Test(expected = LevelOutOfRangeException.class) + public void outOfRange_Lower() throws Exception { + // When + testee.updateZoomLevel(-0.1f); + + // Then + // Expect exception + } + + @Test + public void updateZoomLevel() throws Exception { + // Given + givenZoomSupported(); + + // When + testee.updateZoomLevel(0.5f); + + // Then + verify(cameraDevice).setZoom(0.5f); + } + + @Test + public void zoomNotSupported() throws Exception { + // Given + givenZoomNotSupported(); + + // When + testee.updateZoomLevel(0.5f); + + // Then + verify(cameraDevice, never()).setZoom(anyFloat()); + } + + private void givenZoomNotSupported() { + givenZoom(false); + } + + private void givenZoomSupported() { + givenZoom(true); + } + + private void givenZoom(boolean supported) { + given(cameraDevice.getCapabilities()) + .willReturn(new Capabilities( + Collections.emptySet(), + Collections.emptySet(), + Collections.emptySet(), + Collections.emptySet(), + supported + )); + } + +} \ No newline at end of file diff --git a/fotoapparat/src/test/java/io/fotoapparat/task/GetCapabilitiesTaskTest.java b/fotoapparat/src/test/java/io/fotoapparat/task/GetCapabilitiesTaskTest.java index 87a0f963..5e31ae0c 100644 --- a/fotoapparat/src/test/java/io/fotoapparat/task/GetCapabilitiesTaskTest.java +++ b/fotoapparat/src/test/java/io/fotoapparat/task/GetCapabilitiesTaskTest.java @@ -28,7 +28,8 @@ public class GetCapabilitiesTaskTest { Collections.singleton(new Size(1400, 1080)), Collections.singleton(new Size(1400, 1080)), Collections.singleton(FocusMode.CONTINUOUS_FOCUS), - Collections.singleton(Flash.OFF) + Collections.singleton(Flash.OFF), + false ); @Mock diff --git a/sample/src/main/java/io/fotoapparat/sample/MainActivity.java b/sample/src/main/java/io/fotoapparat/sample/MainActivity.java index 7a2e3dc5..81833b52 100644 --- a/sample/src/main/java/io/fotoapparat/sample/MainActivity.java +++ b/sample/src/main/java/io/fotoapparat/sample/MainActivity.java @@ -7,6 +7,7 @@ import android.view.View; import android.widget.CompoundButton; import android.widget.ImageView; +import android.widget.SeekBar; import android.widget.Toast; import java.io.File; @@ -71,6 +72,7 @@ protected void onCreate(Bundle savedInstanceState) { focusOnLongClick(); switchCameraOnClick(); toggleTorchOnSwitch(); + zoomSeekBar(); } private void setupFotoapparat() { @@ -79,6 +81,29 @@ private void setupFotoapparat() { fotoapparatSwitcher = FotoapparatSwitcher.withDefault(backFotoapparat); } + private void zoomSeekBar() { + SeekBar seekBar = (SeekBar) findViewById(R.id.zoomSeekBar); + + seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + fotoapparatSwitcher + .getCurrentFotoapparat() + .setZoom(progress / (float) seekBar.getMax()); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + // Do nothing + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + // Do nothing + } + }); + } + private void toggleTorchOnSwitch() { SwitchCompat torchSwitch = (SwitchCompat) findViewById(R.id.torchSwitch); diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index bfb4b05e..61f84d31 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -46,4 +46,12 @@ android:layout_gravity="top|left" android:layout_margin="8dp"/> + +