From 1a95195c31c2907725f8e51176a0c54414c1602a Mon Sep 17 00:00:00 2001 From: Azat Akhmetyanov Date: Wed, 24 Feb 2021 13:40:52 +0300 Subject: [PATCH] Revert mediastore updates --- .travis.yml | 2 +- README.md | 8 +- api_client/basic_example.py | 2 +- app/build.gradle | 4 +- .../opencamera/test/MainActivityTest.java | 163 ++++++++---------- .../opencamera/test/SubsetTests.java | 5 +- app/src/main/AndroidManifest.xml | 8 +- .../opencamera/ExtendedAppInterface.java | 43 ----- .../sourceforge/opencamera/ImageSaver.java | 25 +-- .../sourceforge/opencamera/MainActivity.java | 21 +-- .../opencamera/MyApplicationInterface.java | 146 +++++----------- .../sourceforge/opencamera/StorageUtils.java | 14 +- .../opencamera/StorageUtilsWrapper.java | 96 ++--------- .../opencamera/preview/Preview.java | 10 +- .../sensorlogging/RawSensorInfo.java | 102 +++++------ .../sensorlogging/VideoFrameInfo.java | 9 +- .../sensorremote/RemoteRpcRequestHandler.java | 49 +++--- 17 files changed, 222 insertions(+), 485 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6a3c4d5e..66fd581c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,7 +60,7 @@ script: --app $TRAVIS_BUILD_DIR/app/build/outputs/apk/debug/app-debug.apk --test $TRAVIS_BUILD_DIR/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk --device model=blueline,version=28,locale=en,orientation=portrait - --device model=flame,version=30,locale=en,orientation=portrait + --device model=x1q,version=29,locale=en,orientation=portrait --test-targets "class net.sourceforge.opencamera.test.SubsetTests"; fi diff --git a/README.md b/README.md index 94440514..26ef0ca6 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ OpenCamera Sensors is an Android application for synchronized recording of video This project is based on [Open Camera](https://opencamera.org.uk/) — a popular open-source camera application with flexibility in camera parameters settings, actively supported by the community. By regular merging of Open Camera updates our app will adapt to new smartphones and APIs — this is an advantage over the other video + IMU recording applications built from scratch for Camera2API. + ## Usage ![screenshot settings](https://imgur.com/BytzCvA.png) @@ -16,7 +17,7 @@ This project is based on [Open Camera](https://opencamera.org.uk/) — a popul - (Optional) Enable **save frames** option if you want to verify recorded data correctness - **Switch to video**, setup ISO and exposure time - **Record video** -- **Get data** from ```Documents/OpenCamera_Sensors```: +- **Get data** from ```DCIM/OpenCamera```: - Video file - IMU data and frame timestamps in the directory ```{VIDEO_DATE}```: -```{VIDEO_NAME}_gyro.csv```, data format: ```X-data, Y-data, Z-data, timestamp (ns)``` @@ -26,10 +27,7 @@ This project is based on [Open Camera](https://opencamera.org.uk/) — a popul ### Remote recording - **Connect** smartphone to the same network as PC -- Use scripts provided in ```./api_client/``` directory to **send requests** for the application: - - -![remote control methods](https://www.websequencediagrams.com/files/render?link=6txhpHrdgaebT4DYz2C3SaEQjHM1esYDkJZJvPZcgCJHbRAg3c8hqcJYgOmGirze) +- Use scripts provided in ```./api_client/``` directory to **send requests** for the application ## Good practices for data recording diff --git a/api_client/basic_example.py b/api_client/basic_example.py index e67dfc9a..0b345e0b 100644 --- a/api_client/basic_example.py +++ b/api_client/basic_example.py @@ -11,7 +11,7 @@ def main(): remote = RemoteControl(HOST) print("Connected") - accel_data, gyro_data = remote.get_imu(10000, True, True) + accel_data, gyro_data = remote.get_imu(10000, True, False) print("Accelerometer data length: %d" % len(accel_data)) with open("accel.csv", "w+") as accel: accel.writelines(accel_data) diff --git a/app/build.gradle b/app/build.gradle index edf991a7..c8fbd211 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,7 +1,7 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 30 + compileSdkVersion 29 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -11,7 +11,7 @@ android { defaultConfig { applicationId "com.opencamera_extended.app" minSdkVersion 19 - targetSdkVersion 30 + targetSdkVersion 29 renderscriptTargetApi 21 //renderscriptSupportModeEnabled true // don't use support library as it bloats the APK, and we don't need pre-4.4 support diff --git a/app/src/androidTest/java/net/sourceforge/opencamera/test/MainActivityTest.java b/app/src/androidTest/java/net/sourceforge/opencamera/test/MainActivityTest.java index 0249cfce..5e274cf3 100644 --- a/app/src/androidTest/java/net/sourceforge/opencamera/test/MainActivityTest.java +++ b/app/src/androidTest/java/net/sourceforge/opencamera/test/MainActivityTest.java @@ -3546,8 +3546,8 @@ else if( is_expo ) { } private enum UriType { - MEDIASTORE_FILES, MEDIASTORE_IMAGES, + MEDIASTORE_VIDEOS, STORAGE_ACCESS_FRAMEWORK } @@ -3561,12 +3561,12 @@ private List mediaFilesinSaveFolder(Uri baseUri, String bucket_id, UriTy String [] projection; switch( uri_type ) { - case MEDIASTORE_FILES: - projection = new String[] {MediaStore.Files.FileColumns.DISPLAY_NAME}; - break; case MEDIASTORE_IMAGES: projection = new String[] {MediaStore.Images.ImageColumns.DISPLAY_NAME}; break; + case MEDIASTORE_VIDEOS: + projection = new String[] {MediaStore.Video.VideoColumns.DISPLAY_NAME}; + break; case STORAGE_ACCESS_FRAMEWORK: projection = new String[] {DocumentsContract.Document.COLUMN_DISPLAY_NAME}; break; @@ -3576,12 +3576,12 @@ private List mediaFilesinSaveFolder(Uri baseUri, String bucket_id, UriTy String selection = ""; switch( uri_type ) { - case MEDIASTORE_FILES: - selection = MediaStore.Files.FileColumns.BUCKET_ID + " = " + bucket_id; - break; case MEDIASTORE_IMAGES: selection = MediaStore.Images.ImageColumns.BUCKET_ID + " = " + bucket_id; break; + case MEDIASTORE_VIDEOS: + selection = MediaStore.Video.VideoColumns.BUCKET_ID + " = " + bucket_id; + break; case STORAGE_ACCESS_FRAMEWORK: break; default: @@ -3623,8 +3623,8 @@ private List mediaFilesinSaveFolder(Uri baseUri, String bucket_id, UriTy else { String save_folder = mActivity.getStorageUtils().getImageFolderPath(); String bucket_id = String.valueOf(save_folder.toLowerCase().hashCode()); - files.addAll( mediaFilesinSaveFolder(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, bucket_id, UriType.MEDIASTORE_FILES) ); files.addAll( mediaFilesinSaveFolder(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, bucket_id, UriType.MEDIASTORE_IMAGES) ); + files.addAll( mediaFilesinSaveFolder(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, bucket_id, UriType.MEDIASTORE_VIDEOS) ); } if( files.size() == 0 ) { @@ -7826,26 +7826,16 @@ public void testVideoImuInfo() throws InterruptedException { SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(mActivity); SharedPreferences.Editor editor = settings.edit(); editor.putBoolean(PreferenceKeys.IMURecordingPreferenceKey, true); - editor.putBoolean(PreferenceKeys.AccelPreferenceKey, true); - editor.putBoolean(PreferenceKeys.GyroPreferenceKey, true); editor.apply(); updateForSettings(); // count initial files in folder File folder = mActivity.getImageFolder(); - int expectedNFiles; Log.d(TAG, "folder: " + folder); - if (MainActivity.useScopedStorage()) { - // a directory with sensors is not counted as a file - expectedNFiles = 1; - } else { - expectedNFiles = 2; - } - int nNewFiles = subTestTakeVideo(false, false, true, false, null, 5000, false, expectedNFiles - 1); + int expectedNFiles = 1; + int nNewFiles = subTestTakeVideo(false, false, true, false, null, 5000, false, expectedNFiles); - assertEquals(expectedNFiles, nNewFiles); - // check sensor info folder - assertTrue(mActivity.getRawSensorInfoFolder().exists()); + assertEquals(expectedNFiles + 1, nNewFiles); } /* Test recording video with raw IMU sensor info @@ -7861,15 +7851,10 @@ public void testVideoImuInfoSAF() throws InterruptedException { editor.putString(PreferenceKeys.SaveLocationSAFPreferenceKey, "content://com.android.externalstorage.documents/tree/primary%3ADCIM%2FOpenCamera"); editor.apply(); updateForSettings(); - int expectedNFiles; - if (MainActivity.useScopedStorage()) { - expectedNFiles = 1; - } else { - expectedNFiles = 2; - } - int nNewFiles = subTestTakeVideo(false, false, true, false, null, 5000, false, expectedNFiles - 1); + int expectedNFiles = 1; + int nNewFiles = subTestTakeVideo(false, false, true, false, null, 5000, false, expectedNFiles); - assertEquals(expectedNFiles, nNewFiles); + assertEquals(expectedNFiles + 1, nNewFiles); } /* Test recording video with custom gamma profile. @@ -8266,8 +8251,6 @@ public void run() { Log.d(TAG, "check still taking video"); assertTrue( mPreview.isVideoRecording() ); - clickView(takePhotoButton); - int n_new_files = getNFiles() - n_files; Log.d(TAG, "n_new_files: " + n_new_files); assertEquals(1, n_new_files); @@ -10819,7 +10802,7 @@ public void testFolderChooserNew() throws InterruptedException { } FolderChooserDialog fragment = new FolderChooserDialog(); - fragment.setStartFolder(mActivity.getImageFolder()); + fragment.setStartFolder(mActivity.getImageFolder()); fragment.show(mActivity.getFragmentManager(), "FOLDER_FRAGMENT"); Thread.sleep(1000); // wait until folderchooser started up Log.d(TAG, "started folderchooser"); @@ -10850,7 +10833,7 @@ public void testFolderChooserInvalid() throws InterruptedException { } FolderChooserDialog fragment = new FolderChooserDialog(); - fragment.setStartFolder(mActivity.getImageFolder()); + fragment.setStartFolder(mActivity.getImageFolder()); fragment.show(mActivity.getFragmentManager(), "FOLDER_FRAGMENT"); Thread.sleep(1000); // wait until folderchooser started up Log.d(TAG, "started folderchooser"); @@ -11254,7 +11237,7 @@ public void testFailOpenCamera() throws InterruptedException { assertNotNull(mPreview.getCameraControllerManager()); assertNull(mPreview.getCameraController()); this.getInstrumentation().waitForIdleSync(); - + assertFalse( mActivity.popupIsOpen() ); View popupButton = mActivity.findViewById(net.sourceforge.opencamera.R.id.popup); Log.d(TAG, "about to click popup"); @@ -12704,7 +12687,7 @@ private HistogramDetails subTestHDR(List inputs, String output_name, boo HistogramDetails hdrHistogramDetails = null; if( inputs.size() > 1 ) { String preference_hdr_contrast_enhancement = (iso==-1) ? "preference_hdr_contrast_enhancement_always" : "preference_hdr_contrast_enhancement_smart"; - float hdr_alpha = ImageSaver.getHDRAlpha(preference_hdr_contrast_enhancement, exposure_time, inputs.size()); + float hdr_alpha = ImageSaver.getHDRAlpha(preference_hdr_contrast_enhancement, exposure_time, inputs.size()); long time_s = System.currentTimeMillis(); try { mActivity.getApplicationInterface().getHDRProcessor().processHDR(inputs, true, null, true, null, hdr_alpha, 4, true, tonemapping_algorithm, HDRProcessor.DROTonemappingAlgorithm.DROALGORITHM_GAINGAMMA); @@ -12833,7 +12816,7 @@ public void testHDR2() throws IOException, InterruptedException { Log.d(TAG, "testHDR2"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "stlouis/input1.jpg") ); @@ -12854,13 +12837,13 @@ public void testHDR3() throws IOException, InterruptedException { Log.d(TAG, "testHDR3"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR3/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR3/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR3/input2.jpg") ); - + HistogramDetails hdrHistogramDetails = subTestHDR(inputs, "testHDR3_output.jpg", false, 40, 1000000000L/680); int [] exp_offsets_x = {0, 0, 0}; @@ -12878,13 +12861,13 @@ public void testHDR4() throws IOException, InterruptedException { Log.d(TAG, "testHDR4"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR4/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR4/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR4/input2.jpg") ); - + subTestHDR(inputs, "testHDR4_output.jpg", true, 102, 1000000000L/60); int [] exp_offsets_x = {-2, 0, 2}; @@ -12898,13 +12881,13 @@ public void testHDR5() throws IOException, InterruptedException { Log.d(TAG, "testHDR5"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR5/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR5/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR5/input2.jpg") ); - + subTestHDR(inputs, "testHDR5_output.jpg", false, 40, 1000000000L/398); // Nexus 6: @@ -12922,13 +12905,13 @@ public void testHDR6() throws IOException, InterruptedException { Log.d(TAG, "testHDR6"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR6/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR6/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR6/input2.jpg") ); - + subTestHDR(inputs, "testHDR6_output.jpg", false, 40, 1000000000L/2458); int [] exp_offsets_x = {0, 0, 0}; @@ -12942,13 +12925,13 @@ public void testHDR7() throws IOException, InterruptedException { Log.d(TAG, "testHDR7"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR7/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR7/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR7/input2.jpg") ); - + subTestHDR(inputs, "testHDR7_output.jpg", false, 40, 1000000000L/538); int [] exp_offsets_x = {0, 0, 0}; @@ -12962,13 +12945,13 @@ public void testHDR8() throws IOException, InterruptedException { Log.d(TAG, "testHDR8"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR8/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR8/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR8/input2.jpg") ); - + subTestHDR(inputs, "testHDR8_output.jpg", false, 40, 1000000000L/148); int [] exp_offsets_x = {0, 0, 0}; @@ -12982,13 +12965,13 @@ public void testHDR9() throws IOException, InterruptedException { Log.d(TAG, "testHDR9"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR9/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR9/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR9/input2.jpg") ); - + subTestHDR(inputs, "testHDR9_output.jpg", false, 40, 1000000000L/1313); int [] exp_offsets_x = {-1, 0, 1}; @@ -13002,13 +12985,13 @@ public void testHDR10() throws IOException, InterruptedException { Log.d(TAG, "testHDR10"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR10/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR10/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR10/input2.jpg") ); - + subTestHDR(inputs, "testHDR10_output.jpg", false, 107, 1000000000L/120); int [] exp_offsets_x = {2, 0, 0}; @@ -13022,13 +13005,13 @@ public void testHDR11() throws IOException, InterruptedException { Log.d(TAG, "testHDR11"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR11/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR11/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR11/input2.jpg") ); - + HistogramDetails hdrHistogramDetails = subTestHDR(inputs, "testHDR11_output.jpg", true, 40, 1000000000L/2662); int [] exp_offsets_x = {-2, 0, 1}; @@ -13046,13 +13029,13 @@ public void testHDR12() throws IOException, InterruptedException { Log.d(TAG, "testHDR12"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR12/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR12/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR12/input2.jpg") ); - + subTestHDR(inputs, "testHDR12_output.jpg", true, 1196, 1000000000L/12); int [] exp_offsets_x = {0, 0, 7}; @@ -13066,13 +13049,13 @@ public void testHDR13() throws IOException, InterruptedException { Log.d(TAG, "testHDR13"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR13/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR13/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR13/input2.jpg") ); - + subTestHDR(inputs, "testHDR13_output.jpg", false, 323, 1000000000L/24); int [] exp_offsets_x = {0, 0, 2}; @@ -13086,13 +13069,13 @@ public void testHDR14() throws IOException, InterruptedException { Log.d(TAG, "testHDR14"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR14/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR14/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR14/input2.jpg") ); - + subTestHDR(inputs, "testHDR14_output.jpg", false, 40, 1000000000L/1229); int [] exp_offsets_x = {0, 0, 1}; @@ -13106,13 +13089,13 @@ public void testHDR15() throws IOException, InterruptedException { Log.d(TAG, "testHDR15"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR15/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR15/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR15/input2.jpg") ); - + subTestHDR(inputs, "testHDR15_output.jpg", false, 40, 1000000000L/767); int [] exp_offsets_x = {1, 0, -1}; @@ -13126,13 +13109,13 @@ public void testHDR16() throws IOException, InterruptedException { Log.d(TAG, "testHDR16"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR16/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR16/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR16/input2.jpg") ); - + subTestHDR(inputs, "testHDR16_output.jpg", false, 52, 1000000000L/120); int [] exp_offsets_x = {-1, 0, 2}; @@ -13146,13 +13129,13 @@ public void testHDR17() throws IOException, InterruptedException { Log.d(TAG, "testHDR17"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR17/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR17/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR17/input2.jpg") ); - + subTestHDR(inputs, "testHDR17_output.jpg", true, 557, 1000000000L/12); // Nexus 6: @@ -13170,13 +13153,13 @@ public void testHDR18() throws IOException, InterruptedException { Log.d(TAG, "testHDR18"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR18/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR18/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR18/input2.jpg") ); - + HistogramDetails hdrHistogramDetails = subTestHDR(inputs, "testHDR18_output.jpg", true, 100, 1000000000L/800); int [] exp_offsets_x = {0, 0, 0}; @@ -13195,13 +13178,13 @@ public void testHDR19() throws IOException, InterruptedException { Log.d(TAG, "testHDR19"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR19/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR19/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR19/input2.jpg") ); - + subTestHDR(inputs, "testHDR19_output.jpg", true, 100, 1000000000L/160); int [] exp_offsets_x = {0, 0, 0}; @@ -13215,13 +13198,13 @@ public void testHDR20() throws IOException, InterruptedException { Log.d(TAG, "testHDR20"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR20/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR20/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR20/input2.jpg") ); - + subTestHDR(inputs, "testHDR20_output.jpg", true, 100, 1000000000L*2); int [] exp_offsets_x = {0, 0, 0}; @@ -13235,7 +13218,7 @@ public void testHDR21() throws IOException, InterruptedException { Log.d(TAG, "testHDR21"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR21/input0.jpg") ); @@ -13256,13 +13239,13 @@ public void testHDR22() throws IOException, InterruptedException { Log.d(TAG, "testHDR22"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR22/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR22/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR22/input2.jpg") ); - + subTestHDR(inputs, "testHDR22_output.jpg", true, 391, 1000000000L/12); // Nexus 6: @@ -13321,7 +13304,7 @@ public void testHDR23() throws IOException, InterruptedException { Log.d(TAG, "testHDR23"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR23/memorial0068.png") ); @@ -13450,13 +13433,13 @@ public void testHDR24() throws IOException, InterruptedException { Log.d(TAG, "testHDR24"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR24/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR24/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR24/input2.jpg") ); - + subTestHDR(inputs, "testHDR24_output.jpg", true, 40, 1000000000L/422); int [] exp_offsets_x = {0, 0, 1}; @@ -13470,13 +13453,13 @@ public void testHDR25() throws IOException, InterruptedException { Log.d(TAG, "testHDR25"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR25/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR25/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR25/input2.jpg") ); - + subTestHDR(inputs, "testHDR25_output.jpg", true, 40, 1000000000L/1917); int [] exp_offsets_x = {0, 0, 0}; @@ -13490,13 +13473,13 @@ public void testHDR26() throws IOException, InterruptedException { Log.d(TAG, "testHDR26"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR26/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR26/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR26/input2.jpg") ); - + HistogramDetails hdrHistogramDetails = subTestHDR(inputs, "testHDR26_output.jpg", true, 40, 1000000000L/5325); int [] exp_offsets_x = {-1, 0, 1}; @@ -13513,13 +13496,13 @@ public void testHDR27() throws IOException, InterruptedException { Log.d(TAG, "testHDR27"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR27/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR27/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR27/input2.jpg") ); - + subTestHDR(inputs, "testHDR27_output.jpg", true, 40, 1000000000L/949); int [] exp_offsets_x = {0, 0, 2}; @@ -13533,13 +13516,13 @@ public void testHDR28() throws IOException, InterruptedException { Log.d(TAG, "testHDR28"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR28/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR28/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR28/input2.jpg") ); - + subTestHDR(inputs, "testHDR28_output.jpg", true, 294, 1000000000L/20); int [] exp_offsets_x = {0, 0, 2}; @@ -13553,13 +13536,13 @@ public void testHDR29() throws IOException, InterruptedException { Log.d(TAG, "testHDR29"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR29/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR29/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDR29/input2.jpg") ); - + subTestHDR(inputs, "testHDR29_output.jpg", false, 40, 1000000000L/978); int [] exp_offsets_x = {-1, 0, 3}; @@ -14449,13 +14432,13 @@ public void testHDRtemp() throws IOException, InterruptedException { Log.d(TAG, "testHDRtemp"); setToDefault(); - + // list assets List inputs = new ArrayList<>(); inputs.add( getBitmapFromFile(hdr_images_path + "testHDRtemp/input0.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDRtemp/input1.jpg") ); inputs.add( getBitmapFromFile(hdr_images_path + "testHDRtemp/input2.jpg") ); - + subTestHDR(inputs, "testHDRtemp_output.jpg", true, 100, 1000000000L/100); } diff --git a/app/src/androidTest/java/net/sourceforge/opencamera/test/SubsetTests.java b/app/src/androidTest/java/net/sourceforge/opencamera/test/SubsetTests.java index 5d6f6138..668593c3 100644 --- a/app/src/androidTest/java/net/sourceforge/opencamera/test/SubsetTests.java +++ b/app/src/androidTest/java/net/sourceforge/opencamera/test/SubsetTests.java @@ -22,8 +22,9 @@ public static Test suite() { suite.addTest(TestSuite.createTest(MainActivityTest.class, "testTakeVideoSnapshotTimer")); suite.addTest(TestSuite.createTest(MainActivityTest.class, "testTakeVideoSnapshotPausePreview")); suite.addTest(TestSuite.createTest(MainActivityTest.class, "testTakeVideoSnapshotMax")); - // Basic photo tests (without autofocus for instrumentation) - suite.addTest(TestSuite.createTest(MainActivityTest.class, "testTakePhotoNoAutofocus")); + // Basic photo tests + suite.addTest(TestSuite.createTest(MainActivityTest.class, "testTakePhoto")); + suite.addTest(TestSuite.createTest(MainActivityTest.class, "testTakePhotoContinuous")); suite.addTest(TestSuite.createTest(MainActivityTest.class, "testTakePhotoContinuousNoTouch")); return suite; diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cb942f1b..82daf39f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -15,9 +15,8 @@ - + + @@ -33,9 +32,8 @@ android:name=".OpenCameraApplication" android:theme="@style/AppTheme" android:largeHeap="true" + android:requestLegacyExternalStorage="true" > - - = Build.VERSION_CODES.Q ? MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) : MediaStore.Images.Media.EXTERNAL_CONTENT_URI; @@ -2448,27 +2445,7 @@ else if( MainActivity.useScopedStorage() ) { contentValues.put(MediaStore.Images.Media.IS_PENDING, 1); } - saveUri = main_activity.getContentResolver().insert(folder, contentValues);*/ - - contentValues = new ContentValues(); - String picName = storageUtils.createMediaFilename(StorageUtils.MEDIA_TYPE_IMAGE, filename_suffix, 0, "." + extension, request.current_date); - if( MyDebug.LOG ) - Log.d(TAG, "picName: " + picName); - contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, picName); - String mime_type = storageUtils.getImageMimeType(extension); - if( MyDebug.LOG ) - Log.d(TAG, "mime_type: " + mime_type); - contentValues.put(MediaStore.Images.Media.MIME_TYPE, mime_type); - if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ) { - String relative_path = storageUtils.getSaveRelativeFolder(); - if( MyDebug.LOG ) - Log.d(TAG, "relative_path: " + relative_path); - contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, relative_path); - contentValues.put(MediaStore.Images.Media.IS_PENDING, 1); - } - - saveUri = main_activity.getContentResolver().insert(MediaStore.Files.getContentUri("external"), contentValues); - + saveUri = main_activity.getContentResolver().insert(folder, contentValues); if( MyDebug.LOG ) Log.d(TAG, "saveUri: " + saveUri); if( saveUri == null ) { diff --git a/app/src/main/java/net/sourceforge/opencamera/MainActivity.java b/app/src/main/java/net/sourceforge/opencamera/MainActivity.java index 0c1a9c58..74080180 100644 --- a/app/src/main/java/net/sourceforge/opencamera/MainActivity.java +++ b/app/src/main/java/net/sourceforge/opencamera/MainActivity.java @@ -720,9 +720,9 @@ public void onInit(int status) { */ public static boolean useScopedStorage() { // Disable this for our app until this part is integrated properly -// return false; + return false; //return true; - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; + //return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; } public int getNavigationGap() { @@ -1412,7 +1412,6 @@ protected void onResume() { // Create Remote controller for OpenCamera Sensors if (applicationInterface.getRemoteRecControlPref()) { try { - if (mRpcServer != null) mRpcServer.stopExecuting(); mRpcServer = new RemoteRpcServer(this); mRpcServer.start(); Log.d(TAG, "App rpc listener thread started"); @@ -3370,10 +3369,7 @@ public void updateGalleryIcon() { protected Bitmap doInBackground(Void... params) { if( MyDebug.LOG ) Log.d(TAG, "doInBackground"); - StorageUtils.Media media = null; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - media = applicationInterface.getStorageUtils().getLatestMedia(); - } + StorageUtils.Media media = applicationInterface.getStorageUtils().getLatestMedia(); Bitmap thumbnail = null; KeyguardManager keyguard_manager = (KeyguardManager)MainActivity.this.getSystemService(Context.KEYGUARD_SERVICE); boolean is_locked = keyguard_manager != null && keyguard_manager.inKeyguardRestrictedInputMode(); @@ -3597,10 +3593,7 @@ private void openGallery() { if( uri == null ) { if( MyDebug.LOG ) Log.d(TAG, "go to latest media"); - StorageUtils.Media media = null; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - media = applicationInterface.getStorageUtils().getLatestMedia(); - } + StorageUtils.Media media = applicationInterface.getStorageUtils().getLatestMedia(); if( media != null ) { if( MyDebug.LOG ) Log.d(TAG, "latest uri:" + media.uri); @@ -4982,12 +4975,6 @@ public File getImageFolder() { return this.applicationInterface.getStorageUtils().getImageFolder(); } - public File getRawSensorInfoFolder() { - return this.applicationInterface.getStorageUtils().getRawSensorInfoFolder( - applicationInterface.mLastVideoDate - ); - } - public ToastBoxer getChangedAutoStabiliseToastBoxer() { return changed_auto_stabilise_toast; } diff --git a/app/src/main/java/net/sourceforge/opencamera/MyApplicationInterface.java b/app/src/main/java/net/sourceforge/opencamera/MyApplicationInterface.java index 98568282..6241e1d9 100644 --- a/app/src/main/java/net/sourceforge/opencamera/MyApplicationInterface.java +++ b/app/src/main/java/net/sourceforge/opencamera/MyApplicationInterface.java @@ -1,36 +1,11 @@ package net.sourceforge.opencamera; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStreamWriter; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.Timer; -import java.util.TimerTask; - -import net.sourceforge.opencamera.cameracontroller.CameraController; -import net.sourceforge.opencamera.cameracontroller.RawImage; -import net.sourceforge.opencamera.preview.ApplicationInterface; -import net.sourceforge.opencamera.preview.BasicApplicationInterface; -import net.sourceforge.opencamera.preview.Preview; -import net.sourceforge.opencamera.preview.VideoProfile; -import net.sourceforge.opencamera.ui.DrawPreview; -import net.sourceforge.opencamera.ui.FileInfo; - import android.annotation.TargetApi; import android.app.Activity; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -51,7 +26,6 @@ import android.preference.PreferenceManager; import android.provider.DocumentsContract; import android.provider.MediaStore; -import android.provider.OpenableColumns; import android.provider.Settings; import android.util.Log; import android.util.Pair; @@ -59,6 +33,27 @@ import android.view.View; import android.widget.ImageButton; +import net.sourceforge.opencamera.cameracontroller.CameraController; +import net.sourceforge.opencamera.cameracontroller.RawImage; +import net.sourceforge.opencamera.preview.ApplicationInterface; +import net.sourceforge.opencamera.preview.BasicApplicationInterface; +import net.sourceforge.opencamera.preview.Preview; +import net.sourceforge.opencamera.preview.VideoProfile; +import net.sourceforge.opencamera.ui.DrawPreview; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Timer; +import java.util.TimerTask; + /** Our implementation of ApplicationInterface, see there for details. */ public class MyApplicationInterface extends BasicApplicationInterface { @@ -91,8 +86,16 @@ public enum PhotoMode { private boolean panorama_pic_accepted; // whether the last panorama picture was accepted, or else needs to be retaken private boolean panorama_dir_left_to_right = true; // direction of panorama (set after we've captured two images) - protected File last_video_file = null; - protected Uri last_video_file_uri = null; + public File getLastVideoFile() { + if (storageUtils.isUsingSAF()) { + return storageUtils.getFileFromDocumentUriSAF(last_video_file_uri, false); + } else { + return last_video_file; + } + } + + private File last_video_file = null; + private Uri last_video_file_uri = null; private final Timer subtitleVideoTimer = new Timer(); private TimerTask subtitleVideoTimerTask; @@ -338,9 +341,7 @@ public Uri createOutputVideoSAF(String extension) throws IOException { @Override public Uri createOutputVideoMediaStore(String extension) throws IOException { mLastVideoDate = new Date(); - /*Uri folder = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ? - MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) : - MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + Uri folder = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; ContentValues contentValues = new ContentValues(); String filename = storageUtils.createMediaFilename(StorageUtils.MEDIA_TYPE_VIDEO, "", 0, "." + extension, mLastVideoDate); if( MyDebug.LOG ) @@ -350,13 +351,6 @@ public Uri createOutputVideoMediaStore(String extension) throws IOException { if( MyDebug.LOG ) Log.d(TAG, "mime_type: " + mime_type); contentValues.put(MediaStore.Video.Media.MIME_TYPE, mime_type); - if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ) { - String relative_path = storageUtils.getSaveRelativeFolder(); - if( MyDebug.LOG ) - Log.d(TAG, "relative_path: " + relative_path); - contentValues.put(MediaStore.Video.Media.RELATIVE_PATH, relative_path); - contentValues.put(MediaStore.Video.Media.IS_PENDING, 1); - } last_video_file_uri = main_activity.getContentResolver().insert(folder, contentValues); if( MyDebug.LOG ) @@ -364,31 +358,7 @@ public Uri createOutputVideoMediaStore(String extension) throws IOException { if( last_video_file_uri == null ) { throw new IOException(); } -*/ - ContentValues values = new ContentValues(); - String filename = storageUtils.createMediaFilename(StorageUtils.MEDIA_TYPE_VIDEO, "", 0, "." + extension, mLastVideoDate); - if( MyDebug.LOG ) - Log.d(TAG, "filename: " + filename); - values.put(MediaStore.MediaColumns.DISPLAY_NAME, filename); - String mime_type = storageUtils.getVideoMimeType(extension); - if( MyDebug.LOG ) - Log.d(TAG, "mime_type: " + mime_type); - values.put(MediaStore.Video.Media.MIME_TYPE, mime_type); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - values.put( - MediaStore.MediaColumns.RELATIVE_PATH, - storageUtils.getSaveRelativeFolder() - ); - - values.put(MediaStore.Video.Media.IS_PENDING, 1); - } - last_video_file_uri = getContext().getContentResolver().insert(MediaStore.Files.getContentUri("external"), values); - if( MyDebug.LOG ) - Log.d(TAG, "uri: " + last_video_file_uri); - if( last_video_file_uri == null ) { - throw new IOException(); - } return last_video_file_uri; } @@ -2148,9 +2118,7 @@ else if( video_method == VideoMethod.SAF || video_method == VideoMethod.MEDIASTO uri = storageUtils.createOutputFileSAF(subtitle_filename, ""); // don't set a mimetype, as we don't want it to append a new extension } else { - /*Uri folder = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ? - MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) : - MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + Uri folder = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; ContentValues contentValues = new ContentValues(); contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, subtitle_filename); // set mime type - it's unclear if .SRT files have an official mime type, but (a) we must set a mime type otherwise @@ -2158,32 +2126,7 @@ else if( video_method == VideoMethod.SAF || video_method == VideoMethod.MEDIASTO // "java.lang.IllegalArgumentException: MIME type text/plain cannot be inserted into content://media/external_primary/video/media; expected MIME type under video/*" // and we need the file to be saved in the same folder (in DCIM/ ) as the video contentValues.put(MediaStore.Images.Media.MIME_TYPE, "video/x-srt"); - if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ) { - String relative_path = storageUtils.getSaveRelativeFolder(); - if( MyDebug.LOG ) - Log.d(TAG, "relative_path: " + relative_path); - contentValues.put(MediaStore.Video.Media.RELATIVE_PATH, relative_path); - contentValues.put(MediaStore.Video.Media.IS_PENDING, 1); - } uri = main_activity.getContentResolver().insert(folder, contentValues); - if( uri == null ) { - throw new IOException(); - }*/ - ContentValues values = new ContentValues(); - values.put(MediaStore.Video.Media.DISPLAY_NAME, subtitle_filename); - values.put(MediaStore.Images.Media.MIME_TYPE, "text/srt"); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - values.put( - MediaStore.MediaColumns.RELATIVE_PATH, - storageUtils.getSaveRelativeFolder() - ); - - values.put(MediaStore.Video.Media.IS_PENDING, 1); - } - - uri = getContext().getContentResolver().insert(MediaStore.Files.getContentUri("external"), values); - if( MyDebug.LOG ) - Log.d(TAG, "uri: " + uri); if( uri == null ) { throw new IOException(); } @@ -2236,19 +2179,13 @@ public boolean cancel() { if( pfd_saf != null ) { try { pfd_saf.close(); - } - catch(IOException e) { + } catch (IOException e) { e.printStackTrace(); } pfd_saf = null; - } + }/* if( video_method == VideoMethod.MEDIASTORE ) { - if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ) { - ContentValues contentValues = new ContentValues(); - contentValues.put(MediaStore.Video.Media.IS_PENDING, 0); - main_activity.getContentResolver().update(uri, contentValues, null, null); - } - } + }*/ } return super.cancel(); } @@ -2407,15 +2344,10 @@ public void restartedVideo(final VideoMethod video_method, final Uri uri, final * file. */ private void completeVideo(final VideoMethod video_method, final Uri uri) { - if( MyDebug.LOG ) + if (MyDebug.LOG) Log.d(TAG, "completeVideo"); - if( video_method == VideoMethod.MEDIASTORE ) { - if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ) { - ContentValues contentValues = new ContentValues(); - contentValues.put(MediaStore.Video.Media.IS_PENDING, 0); - main_activity.getContentResolver().update(uri, contentValues, null, null); - } - } + /*if( video_method == VideoMethod.MEDIASTORE ) { + }*/ } private boolean broadcastVideo(final VideoMethod video_method, final Uri uri, final String filename) { diff --git a/app/src/main/java/net/sourceforge/opencamera/StorageUtils.java b/app/src/main/java/net/sourceforge/opencamera/StorageUtils.java index 091c18d1..b3b13eb1 100644 --- a/app/src/main/java/net/sourceforge/opencamera/StorageUtils.java +++ b/app/src/main/java/net/sourceforge/opencamera/StorageUtils.java @@ -31,8 +31,6 @@ import androidx.annotation.RequiresApi; import androidx.core.content.ContextCompat; -import net.sourceforge.opencamera.preview.ApplicationInterface; - import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -61,7 +59,7 @@ public class StorageUtils { private final MyApplicationInterface applicationInterface; private Uri last_media_scanned; - private final static String RELATIVE_FOLDER_BASE = Environment.DIRECTORY_DOCUMENTS; + private final static String RELATIVE_FOLDER_BASE = Environment.DIRECTORY_DCIM; // for testing: public volatile boolean failed_to_scan; @@ -276,10 +274,6 @@ public void onScanCompleted(String path, Uri uri) { } } - public ApplicationInterface.VideoMethod createOutputVideoMethod() { - return applicationInterface.createOutputVideoMethod(); - } - /** Wrapper for broadcastFile, when we only have a Uri (e.g., for SAF) */ public void broadcastUri(final Uri uri, final boolean is_new_picture, final boolean is_new_video, final boolean set_last_scanned, final boolean image_capture_intent) { @@ -326,7 +320,7 @@ public boolean isUsingSAF() { // only valid if !isUsingSAF() String getSaveLocation() { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); - return sharedPreferences.getString(PreferenceKeys.SaveLocationPreferenceKey, "OpenCamera_Sensors"); + return sharedPreferences.getString(PreferenceKeys.SaveLocationPreferenceKey, "OpenCamera"); } // only valid if isUsingSAF() @@ -894,7 +888,7 @@ Uri getMediaStoreUri(Context context) { if( this.mediastore ) return this.uri; else { - try { + /*try { // should only have allowed mediastore==null when using scoped storage if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ) { return MediaStore.getMediaUri(context, this.uri); @@ -902,7 +896,7 @@ Uri getMediaStoreUri(Context context) { } catch(Exception e) { e.printStackTrace(); - } + }*/ return null; } } diff --git a/app/src/main/java/net/sourceforge/opencamera/StorageUtilsWrapper.java b/app/src/main/java/net/sourceforge/opencamera/StorageUtilsWrapper.java index 6b7dba2e..83ade887 100644 --- a/app/src/main/java/net/sourceforge/opencamera/StorageUtilsWrapper.java +++ b/app/src/main/java/net/sourceforge/opencamera/StorageUtilsWrapper.java @@ -1,32 +1,20 @@ package net.sourceforge.opencamera; import android.annotation.TargetApi; -import android.content.ContentValues; import android.content.Context; import android.net.Uri; import android.os.Build; -import android.os.Environment; import android.os.ParcelFileDescriptor; -import android.provider.MediaStore; import android.util.Log; -import android.widget.Toast; import androidx.documentfile.provider.DocumentFile; -import net.sourceforge.opencamera.preview.ApplicationInterface; - import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; -import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; -import java.util.Map; - -import static net.sourceforge.opencamera.preview.ApplicationInterface.*; /** * Provides additional functionality for capture information saving @@ -39,78 +27,35 @@ public class StorageUtilsWrapper extends StorageUtils { super(context, applicationInterface); } - public OutputStream createOutputCaptureInfo(int mediaType, String extension, String suffix, Date currentDate) throws IOException { - ApplicationInterface.VideoMethod method = createOutputVideoMethod(); - if (method == ApplicationInterface.VideoMethod.FILE) { - return new FileOutputStream(createOutputCaptureInfoFile(mediaType, suffix, extension, currentDate)); - } else { - Uri outputCaptureInfoUri = createOutputCaptureInfoUri( - mediaType, extension, suffix, currentDate - ); - return getContext().getContentResolver().openOutputStream(outputCaptureInfoUri); - } - } - /** * Creates file with capture information -- sensor, frame timestamps, etc */ - public Uri createOutputCaptureInfoUri(int mediaType, String extension, String suffix, Date currentDate) throws IOException { - VideoMethod videoMethod = createOutputVideoMethod(); - if (videoMethod == VideoMethod.MEDIASTORE) { - return createOutputCaptureInfoFileMediaStore( - mediaType, extension, suffix, currentDate - ); - } else if (videoMethod == VideoMethod.SAF) { - return createOutputCaptureInfoFileSAF( + public File createOutputCaptureInfo(int mediaType, String extension, String suffix, Date currentDate) throws IOException { + if (isUsingSAF()) { + Uri saveUri = createOutputCaptureInfoFileSAF( mediaType, suffix, extension, currentDate ); + File saveFile = getFileFromDocumentUriSAF(saveUri, false); + broadcastFile(saveFile, false, false, true); + return saveFile; } else { - throw new IllegalStateException("Cannot call createCaptureInfoUri when legacy file access is used"); - } - } - - /** - * Creates ouput capture info file if MediaStore is used - */ - public Uri createOutputCaptureInfoFileMediaStore(int mediaType, String extension, String suffix, Date currentDate) { - ContentValues values = new ContentValues(); - String filename = createMediaFilename(mediaType, suffix, 0, "." + extension, currentDate); - values.put(MediaStore.MediaColumns.DISPLAY_NAME, filename); - if (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO_FRAME) { - values.put(MediaStore.MediaColumns.MIME_TYPE, "image/" + extension); - } else if (mediaType == MEDIA_TYPE_RAW_SENSOR_INFO) { - values.put(MediaStore.MediaColumns.MIME_TYPE, "text/" + extension); - } else { - throw new IllegalArgumentException("Provided content type was not supported"); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - values.put( - MediaStore.MediaColumns.RELATIVE_PATH, - Environment.DIRECTORY_DOCUMENTS + - File.separator + - getSaveLocation() + - File.separator + - getRawSensorInfoFolderName(currentDate) + File saveFile = createOutputCaptureInfoFile( + mediaType, suffix, extension, currentDate ); + if (MyDebug.LOG) { + Log.d(TAG, "save to: " + saveFile.getAbsolutePath()); + } + broadcastFile(saveFile, false, false, false); + return saveFile; } - - Uri uri = getContext().getContentResolver().insert(MediaStore.Files.getContentUri("external"), values); - return uri; } /** - * Creates output capture info file if is using SAF + * Creates output capture info file is using SAF */ @TargetApi(Build.VERSION_CODES.LOLLIPOP) - private Uri createOutputCaptureInfoFileSAF(int type, String suffix, String extension, Date currentDate) throws IOException { - String mimeType; - if (type == MEDIA_TYPE_IMAGE || type == MEDIA_TYPE_VIDEO_FRAME) { - mimeType = "image/" + extension; - } else if (type == MEDIA_TYPE_RAW_SENSOR_INFO) { - mimeType = "text/" + extension; - } else { - throw new IllegalArgumentException("Provided content type was not supported"); - } + public Uri createOutputCaptureInfoFileSAF(int type, String suffix, String extension, Date currentDate) throws IOException { + String mimeType = "text/csv"; String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(currentDate); // note that DocumentsContract.createDocument will automatically append to the filename if it already exists String filename = createMediaFilename( @@ -159,14 +104,9 @@ private File getImageFolderChild(String childName) { return file; } - public File getRawSensorInfoFolder(Date currentVideoDate) { - String name = getRawSensorInfoFolderName(currentVideoDate); - return getImageFolderChild(name); - } - - private String getRawSensorInfoFolderName(Date currentVideoDate) { + private File getRawSensorInfoFolder(Date currentVideoDate) { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(currentVideoDate); - return timeStamp; + return getImageFolderChild(timeStamp); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) diff --git a/app/src/main/java/net/sourceforge/opencamera/preview/Preview.java b/app/src/main/java/net/sourceforge/opencamera/preview/Preview.java index 2a7fe8ce..6939c5e2 100644 --- a/app/src/main/java/net/sourceforge/opencamera/preview/Preview.java +++ b/app/src/main/java/net/sourceforge/opencamera/preview/Preview.java @@ -129,7 +129,7 @@ public class Preview implements SurfaceHolder.Callback, TextureView.SurfaceTextu */ private VideoFrameInfo mVideoFrameInfoWriter; private final BlockingQueue mVideoPhaseInfoReporter; - private final BlockingQueue mVideoAvailableReporter; + private final BlockingQueue mVideoAvailableReporter; private RenderScript rs; // lazily created, so we don't take up resources if application isn't using renderscript private ScriptC_histogram_compute histogramScript; // lazily create for performance @@ -196,7 +196,7 @@ enum CameraOpenState { * Important to call close() when the video recording is finished, to free up any resources * (e.g., supplied ParcelFileDescriptor). */ - public static class VideoFileInfo { + private static class VideoFileInfo { private final ApplicationInterface.VideoMethod video_method; private final Uri video_uri; // for VideoMethod.SAF, VideoMethod.URI or VideoMethod.MEDIASTORE private final String video_filename; // for VideoMethod.FILE @@ -415,7 +415,7 @@ enum FaceLocation { public volatile boolean test_runtime_on_video_stop; // force throwing a RuntimeException when stopping video (this usually happens naturally when stopping video too soon) public volatile boolean test_burst_resolution; - public BlockingQueue getVideoAvailableReporter() { + public BlockingQueue getVideoAvailableReporter() { return mVideoAvailableReporter; } @@ -1056,13 +1056,13 @@ private void videoRecordingStopped() { videoFileInfo.close(); applicationInterface.stoppedVideo(videoFileInfo.video_method, videoFileInfo.video_uri, videoFileInfo.video_filename); - if (videoFileInfo != null) mVideoAvailableReporter.add(videoFileInfo); + if (videoFileInfo.video_filename != null) mVideoAvailableReporter.add(videoFileInfo.video_filename); if( nextVideoFileInfo != null ) { // if nextVideoFileInfo is not-null, it means we received MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING but not // MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED, so it is the application responsibility to create the zero-size // video file that will have been created if( MyDebug.LOG ) - Log.d(TAG, "delete unused next video file"); + Log.d(TAG, "delete ununused next video file"); nextVideoFileInfo.close(); applicationInterface.deleteUnusedVideo(nextVideoFileInfo.video_method, nextVideoFileInfo.video_uri, nextVideoFileInfo.video_filename); } diff --git a/app/src/main/java/net/sourceforge/opencamera/sensorlogging/RawSensorInfo.java b/app/src/main/java/net/sourceforge/opencamera/sensorlogging/RawSensorInfo.java index 2f2445eb..6c11a5b9 100644 --- a/app/src/main/java/net/sourceforge/opencamera/sensorlogging/RawSensorInfo.java +++ b/app/src/main/java/net/sourceforge/opencamera/sensorlogging/RawSensorInfo.java @@ -6,25 +6,20 @@ import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.net.Uri; +import android.os.ParcelFileDescriptor; import android.util.Log; import net.sourceforge.opencamera.MainActivity; import net.sourceforge.opencamera.MyDebug; import net.sourceforge.opencamera.StorageUtils; import net.sourceforge.opencamera.StorageUtilsWrapper; -import net.sourceforge.opencamera.preview.ApplicationInterface; +import java.io.BufferedWriter; import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; +import java.io.FileWriter; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.io.PrintWriter; import java.util.Date; -import java.util.HashMap; -import java.util.Map; /** @@ -32,8 +27,8 @@ */ public class RawSensorInfo implements SensorEventListener { private static final String TAG = "RawSensorInfo"; - public static final String SENSOR_TYPE_ACCEL = "accel"; - public static final String SENSOR_TYPE_GYRO = "gyro"; + private static final String SENSOR_TYPE_ACCEL = "accel"; + private static final String SENSOR_TYPE_GYRO = "gyro"; private static final String CSV_SEPARATOR = ","; final private SensorManager mSensorManager; @@ -41,9 +36,8 @@ public class RawSensorInfo implements SensorEventListener { final private Sensor mSensorAccel; private PrintWriter mGyroBufferedWriter; private PrintWriter mAccelBufferedWriter; - private final Map mLastSensorFileUri; - private final Map mLastSensorFile; - + private String mLastGyroPath; + private String mLastAccelPath; private boolean mIsRecording; private final MainActivity mContext; @@ -65,8 +59,6 @@ public RawSensorInfo(MainActivity context) { mSensorGyro = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); mSensorAccel = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); mContext = context; - mLastSensorFile = new HashMap<>(); - mLastSensorFileUri = new HashMap<>(); if (MyDebug.LOG) { Log.d(TAG, "RawSensorInfo"); @@ -115,14 +107,27 @@ public void onAccuracyChanged(Sensor sensor, int accuracy) { // TODO: Add logs for when sensor accuracy decreased } + private void createLastSensorPath(File sensorFile, String sensorType) { + String path = sensorFile.getAbsolutePath(); + switch (sensorType) { + case SENSOR_TYPE_ACCEL: + mLastAccelPath = path; + break; + case SENSOR_TYPE_GYRO: + mLastGyroPath = path; + break; + } + } + /** - * Handles sensor info writer setup, uses StorageUtils to work with SAF, MediaStore and standard file + * Handles sensor info file creation, uses StorageUtils to work both with SAF and standard file * access. */ - private PrintWriter setupRawSensorInfoWriter(String sensorType, - Date date) throws IOException { - StorageUtilsWrapper storageUtils = mContext.getStorageUtils(); - /* try { + private FileWriter getRawSensorInfoFileWriter(MainActivity mainActivity, String sensorType, + Date date) throws IOException { + StorageUtilsWrapper storageUtils = mainActivity.getStorageUtils(); + FileWriter fileWriter; + try { if (storageUtils.isUsingSAF()) { Uri saveUri = storageUtils.createOutputCaptureInfoFileSAF( StorageUtils.MEDIA_TYPE_RAW_SENSOR_INFO, sensorType, "csv", date @@ -145,28 +150,8 @@ private PrintWriter setupRawSensorInfoWriter(String sensorType, createLastSensorPath(saveFile, sensorType); storageUtils.broadcastFile(saveFile, false, false, false); } -*/ try { - ApplicationInterface.VideoMethod method = storageUtils.createOutputVideoMethod(); - OutputStream sensorOutputStream; - if (method == ApplicationInterface.VideoMethod.FILE) { - File outputFile = storageUtils.createOutputCaptureInfoFile(StorageUtils.MEDIA_TYPE_RAW_SENSOR_INFO, sensorType, "csv", date); - if (sensorType.equals(SENSOR_TYPE_ACCEL)) { - mLastSensorFile.put(Sensor.TYPE_ACCELEROMETER, outputFile); - } else if (sensorType.equals(SENSOR_TYPE_GYRO)) { - mLastSensorFile.put(Sensor.TYPE_GYROSCOPE, outputFile); - } - sensorOutputStream = new FileOutputStream(outputFile); - } else { - Uri outputUri = storageUtils.createOutputCaptureInfoUri(StorageUtils.MEDIA_TYPE_RAW_SENSOR_INFO, "csv", sensorType, date); - if (sensorType.equals(SENSOR_TYPE_ACCEL)) { - mLastSensorFileUri.put(Sensor.TYPE_ACCELEROMETER, outputUri); - } else if (sensorType.equals(SENSOR_TYPE_GYRO)) { - mLastSensorFileUri.put(Sensor.TYPE_GYROSCOPE, outputUri); - } - sensorOutputStream = mContext.getContentResolver().openOutputStream(outputUri); - } - return new PrintWriter(sensorOutputStream); + return fileWriter; } catch (IOException e) { e.printStackTrace(); if (MyDebug.LOG) { @@ -176,6 +161,17 @@ private PrintWriter setupRawSensorInfoWriter(String sensorType, } } + private PrintWriter setupRawSensorInfoWriter(String sensorType, + Date date) throws IOException { + FileWriter rawSensorInfoFileWriter = getRawSensorInfoFileWriter( + mContext, sensorType, date + ); + PrintWriter rawSensorInfoWriter = new PrintWriter( + new BufferedWriter(rawSensorInfoFileWriter) + ); + return rawSensorInfoWriter; + } + public void startRecording(Date date) { startRecording(date, true, true); } @@ -259,27 +255,11 @@ public void disableSensors() { mSensorManager.unregisterListener(this); } - public InputStream getLastSensorFileInputStream(Integer sensorType) throws FileNotFoundException { - StorageUtilsWrapper storageUtils = mContext.getStorageUtils(); - ApplicationInterface.VideoMethod method = storageUtils.createOutputVideoMethod(); - if (method == ApplicationInterface.VideoMethod.FILE) { - return new FileInputStream(mLastSensorFile.get(sensorType)); - } else { - return mContext.getContentResolver().openInputStream( - mLastSensorFileUri.get(sensorType) - ); - } + public String getLastGyroPath() { + return mLastGyroPath; } - public String getLastSensorInfoFileName(Integer sensorType) { - StorageUtilsWrapper storageUtils = mContext.getStorageUtils(); - ApplicationInterface.VideoMethod method = storageUtils.createOutputVideoMethod(); - if (method == ApplicationInterface.VideoMethod.FILE) { - return mLastSensorFile.get(sensorType).getName(); - } else { - return mContext.getApplicationInterface().getFileInfoByUri( - mLastSensorFileUri.get(sensorType) - ).getName(); - } + public String getLastAccelPath() { + return mLastAccelPath; } } diff --git a/app/src/main/java/net/sourceforge/opencamera/sensorlogging/VideoFrameInfo.java b/app/src/main/java/net/sourceforge/opencamera/sensorlogging/VideoFrameInfo.java index f95fcb7d..5a30584e 100644 --- a/app/src/main/java/net/sourceforge/opencamera/sensorlogging/VideoFrameInfo.java +++ b/app/src/main/java/net/sourceforge/opencamera/sensorlogging/VideoFrameInfo.java @@ -16,9 +16,7 @@ import java.io.Closeable; import java.io.File; import java.io.FileOutputStream; -import java.io.FileWriter; import java.io.IOException; -import java.io.OutputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Date; @@ -78,7 +76,7 @@ public VideoFrameInfo( durationsNs = new ArrayList<>(); - OutputStream frameTimestampFile = mStorageUtils.createOutputCaptureInfo( + File frameTimestampFile = mStorageUtils.createOutputCaptureInfo( StorageUtils.MEDIA_TYPE_RAW_SENSOR_INFO, "csv", TIMESTAMP_FILE_SUFFIX, mVideoDate ); mFrameBufferedWriter = new BufferedWriter( @@ -130,7 +128,7 @@ public void submitProcessFrame(long timestamp, byte[] imageData, int width, int if (MyDebug.LOG) { Log.d(TAG, "Should save frame, timestamp: " + timestamp); } - OutputStream frameFile = mStorageUtils.createOutputCaptureInfo( + File frameFile = mStorageUtils.createOutputCaptureInfo( StorageUtils.MEDIA_TYPE_VIDEO_FRAME, "jpg", String.valueOf(timestamp), mVideoDate ); writeFrameJpeg(bitmap, frameFile, rotation); @@ -164,7 +162,8 @@ private void writeFrameTimestamp(long timestamp) { } } - private void writeFrameJpeg(Bitmap bitmap, OutputStream fos, int rotation) throws IOException { + private void writeFrameJpeg(Bitmap bitmap, File frameFile, int rotation) throws IOException { + FileOutputStream fos = new FileOutputStream(frameFile); // Apply rotation Matrix matrix = new Matrix(); matrix.postRotate(rotation); diff --git a/app/src/main/java/net/sourceforge/opencamera/sensorremote/RemoteRpcRequestHandler.java b/app/src/main/java/net/sourceforge/opencamera/sensorremote/RemoteRpcRequestHandler.java index 3ffa9e38..922d5e5e 100644 --- a/app/src/main/java/net/sourceforge/opencamera/sensorremote/RemoteRpcRequestHandler.java +++ b/app/src/main/java/net/sourceforge/opencamera/sensorremote/RemoteRpcRequestHandler.java @@ -2,7 +2,6 @@ import android.content.SharedPreferences; import android.hardware.Sensor; -import android.hardware.SensorManager; import android.preference.PreferenceManager; import android.util.Log; @@ -13,15 +12,12 @@ import net.sourceforge.opencamera.preview.Preview; import net.sourceforge.opencamera.sensorlogging.RawSensorInfo; import net.sourceforge.opencamera.sensorlogging.VideoPhaseInfo; -import net.sourceforge.opencamera.ui.FileInfo; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.io.PrintStream; import java.util.Date; import java.util.concurrent.BlockingQueue; @@ -46,11 +42,11 @@ public class RemoteRpcRequestHandler { mRawSensorInfo = context.getRawSensorInfoManager(); } - private String getSensorData(InputStream imuFile, String filename) throws IOException { + private String getSensorData(File imuFile) throws IOException { StringBuilder msg = new StringBuilder(); - msg.append(filename) + msg.append(imuFile.getName()) .append("\n"); - try (BufferedReader br = new BufferedReader(new InputStreamReader(imuFile))) { + try (BufferedReader br = new BufferedReader(new FileReader(imuFile))) { for (String line; (line = br.readLine()) != null; ) { msg.append(line) .append("\n"); @@ -104,28 +100,22 @@ RemoteRpcResponse handleImuRequest(long durationMillis, boolean wantAccel, boole mContext.runOnUiThread(recStopTask); recStopTask.get(); StringBuilder msg = new StringBuilder(); - try { - InputStream imuFile; - if (wantAccel) { - imuFile = mRawSensorInfo.getLastSensorFileInputStream(Sensor.TYPE_ACCELEROMETER); - String imuFilename = mRawSensorInfo.getLastSensorInfoFileName(Sensor.TYPE_ACCELEROMETER); -// File imuFile = new File(mRawSensorInfo.getLastAccelPath()); - msg.append(getSensorData(imuFile, imuFilename)); + if (wantAccel && mRawSensorInfo.getLastAccelPath() != null) { + File imuFile = new File(mRawSensorInfo.getLastAccelPath()); + msg.append(getSensorData(imuFile)); msg.append(SENSOR_DATA_END_MARKER); msg.append("\n"); } - if (wantGyro) { - imuFile = mRawSensorInfo.getLastSensorFileInputStream(Sensor.TYPE_GYROSCOPE); - String imuFilename = mRawSensorInfo.getLastSensorInfoFileName(Sensor.TYPE_GYROSCOPE); -// File imuFile = new File(mRawSensorInfo.getLastGyroPath()); - msg.append(getSensorData(imuFile, imuFilename)); + if (wantGyro && mRawSensorInfo.getLastGyroPath() != null) { + File imuFile = new File(mRawSensorInfo.getLastGyroPath()); + msg.append(getSensorData(imuFile)); msg.append(SENSOR_DATA_END_MARKER); msg.append("\n"); } } catch (IOException e) { e.printStackTrace(); - return RemoteRpcResponse.error("Failed to open requested IMU file", mContext); + return RemoteRpcResponse.error("Failed to open IMU file", mContext); } return RemoteRpcResponse.success(msg.toString(), mContext); @@ -194,10 +184,9 @@ RemoteRpcResponse handleVideoStopRequest() { void handleVideoGetRequest(PrintStream outputStream) { Preview preview = mContext.getPreview(); - BlockingQueue videoReporter; - Log.d(TAG,preview.getVideoAvailableReporter() + "\n"); - - if ((videoReporter = preview.getVideoAvailableReporter()) != null) { + BlockingQueue videoReporter; + if (preview != null && + (videoReporter = preview.getVideoAvailableReporter()) != null) { try { // await available video file if (preview.isVideoRecording()) { @@ -205,17 +194,19 @@ void handleVideoGetRequest(PrintStream outputStream) { } // get file ExtendedAppInterface appInterface = mContext.getApplicationInterface(); - InputStream inputStream = appInterface.getLastVideoFileInputStream(); - FileInfo videoFileInfo = appInterface.getLastVideoFileInfo(); - Log.d(TAG,videoFileInfo.getSize() + "\n" + videoFileInfo.getName() + "\n"); - if (inputStream != null) { + File videoFile = appInterface.getLastVideoFile(); + boolean canRead = videoFile.canRead(); + Log.d(TAG, "yay " + canRead); + if (videoFile != null && videoFile.canRead()) { // Transfer file size in bytes and filename outputStream.println(RemoteRpcResponse.success( - videoFileInfo.getSize() + "\n" + videoFileInfo.getName() + "\n", + videoFile.length() + "\n" + videoFile.getName() + "\n", mContext )); outputStream.flush(); // Transfer file bytes + FileInputStream inputStream = new FileInputStream(videoFile); + byte[] buffer = new byte[BUFFER_SIZE]; int len; while ((len = inputStream.read(buffer)) != -1) {