blob: 9cb4e910dbb8266958f21eb136ee2bfd90e56bfb [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package io.flutter.plugins.camerax;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.graphics.SurfaceTexture;
import android.util.Size;
import android.view.Surface;
import androidx.camera.core.Preview;
import androidx.camera.core.SurfaceRequest;
import androidx.core.util.Consumer;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.ResolutionInfo;
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.SystemServicesFlutterApi.Reply;
import io.flutter.view.TextureRegistry;
import java.util.concurrent.Executor;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class PreviewTest {
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
@Mock public Preview mockPreview;
@Mock public BinaryMessenger mockBinaryMessenger;
@Mock public TextureRegistry mockTextureRegistry;
@Mock public CameraXProxy mockCameraXProxy;
InstanceManager testInstanceManager;
@Before
public void setUp() {
testInstanceManager = spy(InstanceManager.open(identifier -> {}));
}
@After
public void tearDown() {
testInstanceManager.close();
}
@Test
public void create_createsPreviewWithCorrectConfiguration() {
final PreviewHostApiImpl previewHostApi =
new PreviewHostApiImpl(mockBinaryMessenger, testInstanceManager, mockTextureRegistry);
final Preview.Builder mockPreviewBuilder = mock(Preview.Builder.class);
final int targetRotation = 90;
final int targetResolutionWidth = 10;
final int targetResolutionHeight = 50;
final Long previewIdentifier = 3L;
final GeneratedCameraXLibrary.ResolutionInfo resolutionInfo =
new GeneratedCameraXLibrary.ResolutionInfo.Builder()
.setWidth(Long.valueOf(targetResolutionWidth))
.setHeight(Long.valueOf(targetResolutionHeight))
.build();
previewHostApi.cameraXProxy = mockCameraXProxy;
when(mockCameraXProxy.createPreviewBuilder()).thenReturn(mockPreviewBuilder);
when(mockPreviewBuilder.build()).thenReturn(mockPreview);
final ArgumentCaptor<Size> sizeCaptor = ArgumentCaptor.forClass(Size.class);
previewHostApi.create(previewIdentifier, Long.valueOf(targetRotation), resolutionInfo);
verify(mockPreviewBuilder).setTargetRotation(targetRotation);
verify(mockPreviewBuilder).setTargetResolution(sizeCaptor.capture());
assertEquals(sizeCaptor.getValue().getWidth(), targetResolutionWidth);
assertEquals(sizeCaptor.getValue().getHeight(), targetResolutionHeight);
verify(mockPreviewBuilder).build();
verify(testInstanceManager).addDartCreatedInstance(mockPreview, previewIdentifier);
}
@Test
public void setSurfaceProviderTest_createsSurfaceProviderAndReturnsTextureEntryId() {
final PreviewHostApiImpl previewHostApi =
spy(new PreviewHostApiImpl(mockBinaryMessenger, testInstanceManager, mockTextureRegistry));
final TextureRegistry.SurfaceTextureEntry mockSurfaceTextureEntry =
mock(TextureRegistry.SurfaceTextureEntry.class);
final SurfaceTexture mockSurfaceTexture = mock(SurfaceTexture.class);
final Long previewIdentifier = 5L;
final Long surfaceTextureEntryId = 120L;
previewHostApi.cameraXProxy = mockCameraXProxy;
testInstanceManager.addDartCreatedInstance(mockPreview, previewIdentifier);
when(mockTextureRegistry.createSurfaceTexture()).thenReturn(mockSurfaceTextureEntry);
when(mockSurfaceTextureEntry.surfaceTexture()).thenReturn(mockSurfaceTexture);
when(mockSurfaceTextureEntry.id()).thenReturn(surfaceTextureEntryId);
final ArgumentCaptor<Preview.SurfaceProvider> surfaceProviderCaptor =
ArgumentCaptor.forClass(Preview.SurfaceProvider.class);
final ArgumentCaptor<Surface> surfaceCaptor = ArgumentCaptor.forClass(Surface.class);
final ArgumentCaptor<Consumer> consumerCaptor = ArgumentCaptor.forClass(Consumer.class);
// Test that surface provider was set and the surface texture ID was returned.
assertEquals(previewHostApi.setSurfaceProvider(previewIdentifier), surfaceTextureEntryId);
verify(mockPreview).setSurfaceProvider(surfaceProviderCaptor.capture());
verify(previewHostApi).createSurfaceProvider(mockSurfaceTexture);
}
@Test
public void createSurfaceProvider_createsExpectedPreviewSurfaceProvider() {
final PreviewHostApiImpl previewHostApi =
new PreviewHostApiImpl(mockBinaryMessenger, testInstanceManager, mockTextureRegistry);
final SurfaceTexture mockSurfaceTexture = mock(SurfaceTexture.class);
final Surface mockSurface = mock(Surface.class);
final SurfaceRequest mockSurfaceRequest = mock(SurfaceRequest.class);
final SurfaceRequest.Result mockSurfaceRequestResult = mock(SurfaceRequest.Result.class);
final SystemServicesFlutterApiImpl mockSystemServicesFlutterApi =
mock(SystemServicesFlutterApiImpl.class);
final int resolutionWidth = 200;
final int resolutionHeight = 500;
previewHostApi.cameraXProxy = mockCameraXProxy;
when(mockCameraXProxy.createSurface(mockSurfaceTexture)).thenReturn(mockSurface);
when(mockSurfaceRequest.getResolution())
.thenReturn(new Size(resolutionWidth, resolutionHeight));
when(mockCameraXProxy.createSystemServicesFlutterApiImpl(mockBinaryMessenger))
.thenReturn(mockSystemServicesFlutterApi);
final ArgumentCaptor<Surface> surfaceCaptor = ArgumentCaptor.forClass(Surface.class);
final ArgumentCaptor<Consumer> consumerCaptor = ArgumentCaptor.forClass(Consumer.class);
Preview.SurfaceProvider previewSurfaceProvider =
previewHostApi.createSurfaceProvider(mockSurfaceTexture);
previewSurfaceProvider.onSurfaceRequested(mockSurfaceRequest);
verify(mockSurfaceTexture).setDefaultBufferSize(resolutionWidth, resolutionHeight);
verify(mockSurfaceRequest)
.provideSurface(surfaceCaptor.capture(), any(Executor.class), consumerCaptor.capture());
// Test that the surface derived from the surface texture entry will be provided to the surface request.
assertEquals(surfaceCaptor.getValue(), mockSurface);
// Test that the Consumer used to handle surface request result releases Flutter surface texture appropriately
// and sends camera errors appropriately.
Consumer<SurfaceRequest.Result> capturedConsumer = consumerCaptor.getValue();
// Case where Surface should be released.
when(mockSurfaceRequestResult.getResultCode())
.thenReturn(SurfaceRequest.Result.RESULT_REQUEST_CANCELLED);
capturedConsumer.accept(mockSurfaceRequestResult);
verify(mockSurface).release();
reset(mockSurface);
when(mockSurfaceRequestResult.getResultCode())
.thenReturn(SurfaceRequest.Result.RESULT_REQUEST_CANCELLED);
capturedConsumer.accept(mockSurfaceRequestResult);
verify(mockSurface).release();
reset(mockSurface);
when(mockSurfaceRequestResult.getResultCode())
.thenReturn(SurfaceRequest.Result.RESULT_WILL_NOT_PROVIDE_SURFACE);
capturedConsumer.accept(mockSurfaceRequestResult);
verify(mockSurface).release();
reset(mockSurface);
when(mockSurfaceRequestResult.getResultCode())
.thenReturn(SurfaceRequest.Result.RESULT_SURFACE_USED_SUCCESSFULLY);
capturedConsumer.accept(mockSurfaceRequestResult);
verify(mockSurface).release();
reset(mockSurface);
// Case where error must be sent.
when(mockSurfaceRequestResult.getResultCode())
.thenReturn(SurfaceRequest.Result.RESULT_INVALID_SURFACE);
capturedConsumer.accept(mockSurfaceRequestResult);
verify(mockSurface).release();
verify(mockSystemServicesFlutterApi).sendCameraError(anyString(), any(Reply.class));
}
@Test
public void releaseFlutterSurfaceTexture_makesCallToReleaseFlutterSurfaceTexture() {
final PreviewHostApiImpl previewHostApi =
new PreviewHostApiImpl(mockBinaryMessenger, testInstanceManager, mockTextureRegistry);
final TextureRegistry.SurfaceTextureEntry mockSurfaceTextureEntry =
mock(TextureRegistry.SurfaceTextureEntry.class);
previewHostApi.flutterSurfaceTexture = mockSurfaceTextureEntry;
previewHostApi.releaseFlutterSurfaceTexture();
verify(mockSurfaceTextureEntry).release();
}
@Test
public void getResolutionInfo_makesCallToRetrievePreviewResolutionInfo() {
final PreviewHostApiImpl previewHostApi =
new PreviewHostApiImpl(mockBinaryMessenger, testInstanceManager, mockTextureRegistry);
final androidx.camera.core.ResolutionInfo mockResolutionInfo =
mock(androidx.camera.core.ResolutionInfo.class);
final Long previewIdentifier = 23L;
final int resolutionWidth = 500;
final int resolutionHeight = 200;
testInstanceManager.addDartCreatedInstance(mockPreview, previewIdentifier);
when(mockPreview.getResolutionInfo()).thenReturn(mockResolutionInfo);
when(mockResolutionInfo.getResolution())
.thenReturn(new Size(resolutionWidth, resolutionHeight));
ResolutionInfo resolutionInfo = previewHostApi.getResolutionInfo(previewIdentifier);
assertEquals(resolutionInfo.getWidth(), Long.valueOf(resolutionWidth));
assertEquals(resolutionInfo.getHeight(), Long.valueOf(resolutionHeight));
}
}