0
0
mirror of https://git.code.sf.net/p/opencamera/code.git synced 2024-09-20 03:52:26 +02:00

New VideoTestSuite and testTakeVideoAltResolution().

This commit is contained in:
Mark Harman 2024-04-02 22:30:51 +01:00
parent a01c8be4b8
commit 5800c68b7e
3 changed files with 298 additions and 1 deletions

View File

@ -5,6 +5,7 @@ import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.endsWith;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@ -13,6 +14,7 @@ import android.annotation.TargetApi;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.media.CamcorderProfile;
import android.os.Build; import android.os.Build;
import android.os.Looper; import android.os.Looper;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
@ -24,6 +26,7 @@ import androidx.test.espresso.matcher.ViewMatchers;
import androidx.test.ext.junit.rules.ActivityScenarioRule; import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import net.sourceforge.opencamera.preview.Preview;
import net.sourceforge.opencamera.ui.DrawPreview; import net.sourceforge.opencamera.ui.DrawPreview;
import net.sourceforge.opencamera.ui.PopupView; import net.sourceforge.opencamera.ui.PopupView;
@ -36,11 +39,14 @@ import org.junit.runner.RunWith;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
interface PhotoTests {} interface PhotoTests {}
interface VideoTests {}
interface HDRTests {} interface HDRTests {}
interface HDRNTests {} interface HDRNTests {}
@ -137,6 +143,34 @@ public class InstrumentedTest {
} }
} }
private void waitUntilTimer() {
Log.d(TAG, "wait until timer stopped");
boolean done = false;
while( !done ) {
done = getActivityValue(activity -> !activity.getPreview().isOnTimer());
}
}
private void pauseAndResume() {
Log.d(TAG, "pauseAndResume");
boolean camera_is_open = getActivityValue(activity -> activity.getPreview().getCameraController() != null);
pauseAndResume(camera_is_open);
}
private void pauseAndResume(boolean wait_until_camera_opened) {
Log.d(TAG, "pauseAndResume: " + wait_until_camera_opened);
mActivityRule.getScenario().onActivity(activity -> {
Log.d(TAG, "pause...");
getInstrumentation().callActivityOnPause(activity);
Log.d(TAG, "resume...");
getInstrumentation().callActivityOnResume(activity);
});
if( wait_until_camera_opened ) {
waitUntilCameraOpened();
}
}
private void updateForSettings(MainActivity activity) { private void updateForSettings(MainActivity activity) {
Log.d(TAG, "updateForSettings"); Log.d(TAG, "updateForSettings");
assertEquals(Looper.getMainLooper().getThread(), Thread.currentThread()); // check on UI thread assertEquals(Looper.getMainLooper().getThread(), Thread.currentThread()); // check on UI thread
@ -6335,4 +6369,254 @@ public class InstrumentedTest {
} }
}); });
} }
private int getNFiles() {
// count initial files in folder
String [] files = getActivityValue(activity -> TestUtils.filesInSaveFolder(activity));
Log.d(TAG, "getNFiles: " + Arrays.toString(files));
return files == null ? 0 : files.length;
}
/**
* @return The number of resultant video files
*/
private int subTestTakeVideo(boolean test_exposure_lock, boolean test_focus_area, boolean allow_failure, boolean immersive_mode, TestUtils.VideoTestCallback test_cb, long time_ms, boolean max_filesize, int n_non_video_files) throws InterruptedException {
boolean supports_exposure_lock = getActivityValue(activity -> activity.getPreview().supportsExposureLock());
if( test_exposure_lock && !supports_exposure_lock ) {
return 0;
}
Thread.sleep(500); // needed for Pixel 6 Pro with Camera 2 API
mActivityRule.getScenario().onActivity(activity -> {
TestUtils.preTakeVideoChecks(activity, immersive_mode);
if( !activity.getPreview().isVideo() ) {
View switchVideoButton = activity.findViewById(net.sourceforge.opencamera.R.id.switch_video);
clickView(switchVideoButton);
}
});
waitUntilCameraOpened();
mActivityRule.getScenario().onActivity(activity -> {
assertTrue(activity.getPreview().isVideo());
TestUtils.preTakeVideoChecks(activity, immersive_mode);
// reset:
activity.getApplicationInterface().test_n_videos_scanned = 0;
});
// count initial files in folder
int n_files = getNFiles();
Log.d(TAG, "n_files at start: " + n_files);
// store status to compare with later
int exposureVisibility = getActivityValue(activity -> {
View exposureButton = activity.findViewById(net.sourceforge.opencamera.R.id.exposure);
return exposureButton.getVisibility();
});
int exposureLockVisibility = getActivityValue(activity -> {
View exposureLockButton = activity.findViewById(net.sourceforge.opencamera.R.id.exposure_lock);
return exposureLockButton.getVisibility();
});
mActivityRule.getScenario().onActivity(activity -> {
Log.d(TAG, "about to click take video");
View takePhotoButton = activity.findViewById(net.sourceforge.opencamera.R.id.take_photo);
clickView(takePhotoButton);
Log.d(TAG, "done clicking take video");
});
getInstrumentation().waitForIdleSync();
Log.d(TAG, "after idle sync");
mActivityRule.getScenario().onActivity(activity -> {
Preview preview = activity.getPreview();
if( preview.usingCamera2API() ) {
assertEquals(preview.getCurrentPreviewSize().width, preview.getCameraController().test_texture_view_buffer_w);
assertEquals(preview.getCurrentPreviewSize().height, preview.getCameraController().test_texture_view_buffer_h);
}
});
waitUntilTimer();
int exp_n_new_files = 0;
boolean failed_to_start = false;
boolean is_video_recording = getActivityValue(activity -> activity.getPreview().isVideoRecording());
if( is_video_recording ) {
mActivityRule.getScenario().onActivity(activity -> {
TestUtils.takeVideoRecordingChecks(activity, immersive_mode, exposureVisibility, exposureLockVisibility);
});
if( test_cb == null ) {
if( !immersive_mode && time_ms > 500 ) {
// test turning torch on/off (if in immersive mode, popup button will be hidden)
switchToFlashValue("flash_torch");
Thread.sleep(500);
switchToFlashValue("flash_off");
}
Thread.sleep(time_ms);
mActivityRule.getScenario().onActivity(activity -> {
TestUtils.takeVideoRecordingChecks(activity, immersive_mode, exposureVisibility, exposureLockVisibility);
Preview preview = activity.getPreview();
assertFalse(preview.hasFocusArea());
if( !allow_failure ) {
assertNull(preview.getCameraController().getFocusAreas());
assertNull(preview.getCameraController().getMeteringAreas());
}
});
if( test_focus_area ) {
// touch to auto-focus with focus area
Log.d(TAG, "touch to focus");
onView(anyOf(ViewMatchers.withClassName(endsWith("MySurfaceView")), ViewMatchers.withClassName(endsWith("MyTextureView")))).perform(click());
Log.d(TAG, "done touch to focus");
Thread.sleep(1000); // wait for autofocus
mActivityRule.getScenario().onActivity(activity -> {
Preview preview = activity.getPreview();
if( preview.supportsFocus() ) {
assertTrue(preview.hasFocusArea());
assertNotNull(preview.getCameraController().getFocusAreas());
assertEquals(1, preview.getCameraController().getFocusAreas().size());
assertNotNull(preview.getCameraController().getMeteringAreas());
assertEquals(1, preview.getCameraController().getMeteringAreas().size());
}
});
// this time, don't wait
Log.d(TAG, "touch again to focus");
onView(anyOf(ViewMatchers.withClassName(endsWith("MySurfaceView")), ViewMatchers.withClassName(endsWith("MyTextureView")))).perform(click());
Log.d(TAG, "done touch to focus");
}
if( test_exposure_lock ) {
mActivityRule.getScenario().onActivity(activity -> {
Log.d(TAG, "test exposure lock");
assertFalse(activity.getPreview().getCameraController().getAutoExposureLock());
View exposureLockButton = activity.findViewById(net.sourceforge.opencamera.R.id.exposure_lock);
clickView(exposureLockButton);
});
getInstrumentation().waitForIdleSync();
Log.d(TAG, "after idle sync");
mActivityRule.getScenario().onActivity(activity -> {
assertTrue( activity.getPreview().getCameraController().getAutoExposureLock() );
});
Thread.sleep(2000);
}
mActivityRule.getScenario().onActivity(activity -> {
TestUtils.takeVideoRecordingChecks(activity, immersive_mode, exposureVisibility, exposureLockVisibility);
Log.d(TAG, "about to click stop video");
View takePhotoButton = activity.findViewById(net.sourceforge.opencamera.R.id.take_photo);
clickView(takePhotoButton);
Log.d(TAG, "done clicking stop video");
});
getInstrumentation().waitForIdleSync();
Log.d(TAG, "after idle sync");
}
else {
exp_n_new_files = test_cb.doTest();
mActivityRule.getScenario().onActivity(activity -> {
if( activity.getPreview().isVideoRecording() ) {
Log.d(TAG, "about to click stop video");
View takePhotoButton = activity.findViewById(net.sourceforge.opencamera.R.id.take_photo);
clickView(takePhotoButton);
Log.d(TAG, "done clicking stop video");
}
});
getInstrumentation().waitForIdleSync();
Log.d(TAG, "after idle sync");
}
}
else {
Log.d(TAG, "didn't start video");
assertTrue(allow_failure);
failed_to_start = true;
}
int n_new_files = getNFiles() - n_files;
Log.d(TAG, "n_new_files: " + n_new_files);
int exp_n_new_files_f = exp_n_new_files;
boolean failed_to_start_f = failed_to_start;
mActivityRule.getScenario().onActivity(activity -> {
TestUtils.checkFilesAfterTakeVideo(activity, allow_failure, test_cb != null, time_ms, n_non_video_files, failed_to_start_f, exp_n_new_files_f, n_new_files);
TestUtils.postTakeVideoChecks(activity, immersive_mode, max_filesize, exposureVisibility, exposureLockVisibility);
});
return n_new_files;
}
/*@Category(VideoTests.class)
@Test
public void testTakeVideo() throws InterruptedException {
Log.d(TAG, "testTakeVideo");
setToDefault();
int n_new_files = subTestTakeVideo(false, false, false, false, null, 5000, false, 0);
assertEquals(1, n_new_files);
}*/
/** Test for bug fix made on 20221112, to do with Pixel 6 Pro and video resolution larger than
* FullHD but smaller than 4K. Problem that we selected 60fps because that's supported at
* FullHD (and is in the CamcorderProfile for FullHD), but the larger non-4K resolution does
* not support 60fps.
*/
@Category(VideoTests.class)
@Test
public void testTakeVideoAltResolution() throws InterruptedException {
Log.d(TAG, "testTakeVideoAltResolution");
setToDefault();
if( !getActivityValue(activity -> activity.getPreview().usingCamera2API()) ) {
return;
}
String chosen_video_quality = getActivityValue(activity -> {
String return_quality = null;
CamcorderProfile best_profile = null;
List<String> supported_video_quality = activity.getPreview().getVideoQualityHander().getSupportedVideoQuality();
if( supported_video_quality != null ) {
for(String quality : supported_video_quality) {
CamcorderProfile profile = activity.getPreview().getCamcorderProfile(quality);
if( profile.videoFrameWidth > 1920 && profile.videoFrameHeight > 1080 && profile.videoFrameWidth < 3840 && profile.videoFrameHeight < 2160 ) {
if( best_profile == null || profile.videoFrameWidth*profile.videoFrameHeight < best_profile.videoFrameWidth*best_profile.videoFrameHeight ) {
return_quality = quality;
best_profile = profile;
}
}
}
}
if( return_quality != null ) {
Log.d(TAG, "video_quality: " + return_quality);
Log.d(TAG, "best_profile: " + best_profile.videoFrameWidth + " x " + best_profile.videoFrameHeight);
}
return return_quality;
});
if( chosen_video_quality == null ) {
Log.d(TAG, "can't find desired video resolution");
return;
}
mActivityRule.getScenario().onActivity(activity -> {
activity.getApplicationInterface().setVideoQualityPref(chosen_video_quality);
});
int n_new_files = subTestTakeVideo(false, false, false, false, null, 5000, false, 0);
assertEquals(1, n_new_files);
pauseAndResume();
mActivityRule.getScenario().onActivity(activity -> {
String video_quality = activity.getApplicationInterface().getVideoQualityPref();
Log.d(TAG, "video_quality: " + video_quality);
assertEquals(chosen_video_quality, video_quality);
});
}
} }

View File

@ -0,0 +1,13 @@
package net.sourceforge.opencamera;
import org.junit.experimental.categories.Categories;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
/** Tests related to video recording; note that tests to do with video mode that don't record are still part of MainTests.
*/
@RunWith(Categories.class)
@Categories.IncludeCategory(VideoTests.class)
@Suite.SuiteClasses({InstrumentedTest.class})
public class VideoTestSuite {}

View File

@ -3391,7 +3391,7 @@ public class Preview implements SurfaceHolder.Callback, TextureView.SurfaceTextu
* this might be called even in slow motion mode), since we use this for things like setting up * this might be called even in slow motion mode), since we use this for things like setting up
* available preferences. * available preferences.
*/ */
private CamcorderProfile getCamcorderProfile(String quality) { public CamcorderProfile getCamcorderProfile(String quality) {
if( MyDebug.LOG ) if( MyDebug.LOG )
Log.d(TAG, "getCamcorderProfile(): " + quality); Log.d(TAG, "getCamcorderProfile(): " + quality);
if( camera_controller == null ) { if( camera_controller == null ) {