blob: 34d0b41e3b3161b1f8fb8df04fd50c36570d9d2d [file] [log] [blame]
/*
* Copyright 2021 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 androidx.camera.view;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.Build;
import android.util.Size;
import android.view.Window;
import android.widget.FrameLayout;
import androidx.camera.core.CameraInfo;
import androidx.camera.core.ImageCapture.ScreenFlashUiControl;
import androidx.camera.core.SurfaceRequest;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.testing.fakes.FakeCamera;
import androidx.camera.testing.fakes.FakeCameraInfoInternal;
import androidx.camera.view.internal.compat.quirk.QuirkInjector;
import androidx.camera.view.internal.compat.quirk.SurfaceViewNotCroppedByParentQuirk;
import androidx.camera.view.internal.compat.quirk.SurfaceViewStretchedQuirk;
import androidx.test.core.app.ApplicationProvider;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.internal.DoNotInstrument;
import org.robolectric.shadows.ShadowWindow;
@RunWith(RobolectricTestRunner.class)
@DoNotInstrument
@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
public class PreviewViewTest {
private final Context mAppContext = ApplicationProvider.getApplicationContext();
private PreviewView mPreviewView;
private Window mWindow;
@Before
public void setUp() {
mPreviewView = new PreviewView(mAppContext);
try {
mWindow = ShadowWindow.create(mAppContext);
} catch (ClassNotFoundException e) {
Assume.assumeTrue("Failed to create shadow window", false);
}
}
@After
public void tearDown() {
QuirkInjector.clear();
}
@Test
@Config(minSdk = Build.VERSION_CODES.N_MR1)
public void surfaceViewNormal_useSurfaceView() {
// Assert: SurfaceView is used.
assertThat(PreviewView.shouldUseTextureView(
createSurfaceRequestCompatibleWithSurfaceView(),
PreviewView.ImplementationMode.PERFORMANCE)).isFalse();
}
@Test
public void surfaceViewStretchedQuirk_useTextureView() {
// Arrange:
QuirkInjector.inject(new SurfaceViewStretchedQuirk());
// Assert: TextureView is used even the SurfaceRequest is compatible with SurfaceView.
assertThat(PreviewView.shouldUseTextureView(
createSurfaceRequestCompatibleWithSurfaceView(),
PreviewView.ImplementationMode.PERFORMANCE)).isTrue();
}
@Test
public void surfaceViewNotCroppedQuirk_useTextureView() {
// Arrange:
QuirkInjector.inject(new SurfaceViewNotCroppedByParentQuirk());
// Assert: TextureView is used even the SurfaceRequest is compatible with SurfaceView.
assertThat(PreviewView.shouldUseTextureView(
createSurfaceRequestCompatibleWithSurfaceView(),
PreviewView.ImplementationMode.PERFORMANCE)).isTrue();
}
@Test
@Config(minSdk = Build.VERSION_CODES.N_MR1)
public void surfaceView_reuseImplementation() {
// Arrange:
FrameLayout parent = new FrameLayout(ApplicationProvider.getApplicationContext());
PreviewTransformation transformation = new PreviewTransformation();
// Assert: The implementation should be reused if it is a SurfaceViewImplementation and
// other requirements are compatible with SurfaceView.
assertThat(PreviewView.shouldReuseImplementation(
new SurfaceViewImplementation(parent, transformation),
createSurfaceRequestCompatibleWithSurfaceView(),
PreviewView.ImplementationMode.PERFORMANCE)).isTrue();
}
@Test
@Config(minSdk = Build.VERSION_CODES.N_MR1)
public void surfaceView_notReuseImplementation_whenNull() {
// Assert: The implementation should not be reused if it is null.
assertThat(PreviewView.shouldReuseImplementation(
null,
createSurfaceRequestCompatibleWithSurfaceView(),
PreviewView.ImplementationMode.PERFORMANCE)).isFalse();
}
@Test
public void textureView_notReuseImplementation() {
// Arrange:
FrameLayout parent = new FrameLayout(ApplicationProvider.getApplicationContext());
PreviewTransformation transformation = new PreviewTransformation();
// Assert: The implementation should not be reused if it is a TextureViewImplementation.
assertThat(PreviewView.shouldReuseImplementation(
new TextureViewImplementation(parent, transformation),
createSurfaceRequestCompatibleWithSurfaceView(),
PreviewView.ImplementationMode.COMPATIBLE)).isFalse();
}
@Test(expected = IllegalArgumentException.class)
public void setFrameUpdateListener_afterPerformanceModeSet() {
PreviewView previewView = new PreviewView(ApplicationProvider.getApplicationContext());
previewView.setImplementationMode(PreviewView.ImplementationMode.PERFORMANCE);
previewView.setFrameUpdateListener(CameraXExecutors.mainThreadExecutor(),
(timestamp) -> {});
}
@Test(expected = IllegalArgumentException.class)
public void setFrameUpdateListener_beforePerformanceModeSet() {
PreviewView previewView = new PreviewView(ApplicationProvider.getApplicationContext());
previewView.setFrameUpdateListener(CameraXExecutors.mainThreadExecutor(),
(timestamp) -> {});
previewView.setImplementationMode(PreviewView.ImplementationMode.PERFORMANCE);
}
@Test
public void canCreateValidScreenFlashUiControlImpl() {
ScreenFlashUiControl uiControl = createScreenFlashUiControl(false);
assertThat(uiControl).isNotNull();
}
@Test
public void validScreenFlashUiControlSetToCameraController_whenWindowSetAndThenControllerSet() {
CameraController cameraController = new LifecycleCameraController(mAppContext);
mPreviewView.setScreenFlashWindow(mWindow);
mPreviewView.setController(cameraController);
assertThat(cameraController.getScreenFlashUiInfoByPriority()).isNotNull();
assertThat(
cameraController.getScreenFlashUiInfoByPriority().getScreenFlashUiControl()
).isNotNull();
}
@Test
public void validScreenFlashUiControlSetToCameraController_whenControllerSetAndThenWindowSet() {
CameraController cameraController = new LifecycleCameraController(mAppContext);
mPreviewView.setController(cameraController);
mPreviewView.setScreenFlashWindow(mWindow);
assertThat(cameraController.getScreenFlashUiInfoByPriority()).isNotNull();
assertThat(
cameraController.getScreenFlashUiInfoByPriority().getScreenFlashUiControl()
).isNotNull();
}
@Test
public void nullScreenFlashUiControlSetToCameraController_whenControllerSetButNoWindowSet() {
CameraController cameraController = new LifecycleCameraController(mAppContext);
mPreviewView.setController(cameraController);
if (cameraController.getScreenFlashUiInfoByPriority() != null) {
assertThat(
cameraController.getScreenFlashUiInfoByPriority().getScreenFlashUiControl()
).isNull();
}
}
private SurfaceRequest createSurfaceRequestCompatibleWithSurfaceView() {
FakeCameraInfoInternal cameraInfoInternal = new FakeCameraInfoInternal();
cameraInfoInternal.setImplementationType(CameraInfo.IMPLEMENTATION_TYPE_CAMERA2);
return new SurfaceRequest(new Size(800, 600),
new FakeCamera(null, cameraInfoInternal), () -> {});
}
private ScreenFlashUiControl createScreenFlashUiControl(boolean assumeNoFailure) {
mPreviewView.setScreenFlashWindow(mWindow);
ScreenFlashUiControl uiControl = mPreviewView.getScreenFlashUiControl();
if (assumeNoFailure) {
Assume.assumeTrue("Failed to create ScreenFlashUiControl", uiControl != null);
}
return uiControl;
}
}