From 8b804c411cd17a0e2d108ab23c3c62a8f48639e7 Mon Sep 17 00:00:00 2001 From: Azat Akhmetyanov Date: Tue, 26 Jan 2021 19:03:40 +0300 Subject: [PATCH 01/16] Move sensor preferences to separate preference screen --- app/src/main/res/xml/preferences.xml | 72 +++++++++++++++------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 83b36af8..b7beec73 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -75,47 +75,53 @@ android:summary="Enable synchronized IMU and video recording with timestamps" /> - - - - - + + - + - + + + + + + Date: Wed, 27 Jan 2021 14:11:18 +0300 Subject: [PATCH 02/16] Restructure RawSensorInfo.java; Add magnetometer recording --- .../opencamera/ExtendedAppInterface.java | 4 +- .../sourceforge/opencamera/MainActivity.java | 13 +- .../opencamera/MyPreferenceFragment.java | 7 + .../opencamera/PreferenceKeys.java | 4 + .../sensorlogging/RawSensorInfo.java | 142 +++++++++++++----- app/src/main/res/xml/preferences.xml | 6 + 6 files changed, 135 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java b/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java index ce633ba3..be8a4398 100644 --- a/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java +++ b/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java @@ -107,7 +107,9 @@ public void startingVideo() { } } - mRawSensorInfo.startRecording(mMainActivity, mLastVideoDate, getGyroPref(), getAccelPref()); + //mRawSensorInfo.startRecording(mMainActivity, mLastVideoDate, get Pref(), getAccelPref()) + // TODO: create map with magnetometer option + mRawSensorInfo.startRecording(mMainActivity, mLastVideoDate); // TODO: add message to strings.xml mMainActivity.getPreview().showToast(null, "Starting video with IMU recording"); } catch (NumberFormatException e) { diff --git a/app/src/main/java/net/sourceforge/opencamera/MainActivity.java b/app/src/main/java/net/sourceforge/opencamera/MainActivity.java index b4f75464..f8bbe3ca 100644 --- a/app/src/main/java/net/sourceforge/opencamera/MainActivity.java +++ b/app/src/main/java/net/sourceforge/opencamera/MainActivity.java @@ -715,7 +715,7 @@ public void onInit(int status) { public static boolean useScopedStorage() { //return false; //return true; - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; + return false; } public int getNavigationGap() { @@ -2293,6 +2293,7 @@ public void openSettings() { Bundle bundle = new Bundle(); bundle.putBoolean(PreferenceKeys.SupportsGyroKey, mRawSensorInfo.isSensorAvailable(Sensor.TYPE_GYROSCOPE)); bundle.putBoolean(PreferenceKeys.SupportsAccelKey, mRawSensorInfo.isSensorAvailable(Sensor.TYPE_ACCELEROMETER)); + bundle.putBoolean(PreferenceKeys.SupportsMagnetometerKey, mRawSensorInfo.isSensorAvailable(Sensor.TYPE_MAGNETIC_FIELD)); bundle.putInt("cameraId", this.preview.getCameraId()); bundle.putInt("nCameras", preview.getCameraControllerManager().getNumberOfCameras()); @@ -3344,7 +3345,10 @@ public void updateGalleryIcon() { protected Bitmap doInBackground(Void... params) { if( MyDebug.LOG ) Log.d(TAG, "doInBackground"); - StorageUtils.Media media = applicationInterface.getStorageUtils().getLatestMedia(); + StorageUtils.Media media = null; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + 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(); @@ -3568,7 +3572,10 @@ private void openGallery() { if( uri == null ) { if( MyDebug.LOG ) Log.d(TAG, "go to latest media"); - StorageUtils.Media media = applicationInterface.getStorageUtils().getLatestMedia(); + StorageUtils.Media media = null; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + media = applicationInterface.getStorageUtils().getLatestMedia(); + } if( media != null ) { if( MyDebug.LOG ) Log.d(TAG, "latest uri:" + media.uri); diff --git a/app/src/main/java/net/sourceforge/opencamera/MyPreferenceFragment.java b/app/src/main/java/net/sourceforge/opencamera/MyPreferenceFragment.java index 24f78f79..622760c3 100644 --- a/app/src/main/java/net/sourceforge/opencamera/MyPreferenceFragment.java +++ b/app/src/main/java/net/sourceforge/opencamera/MyPreferenceFragment.java @@ -127,6 +127,13 @@ public void onCreate(Bundle savedInstanceState) { gyroPref.setChecked(false); gyroPref.setEnabled(false); } + + final boolean supports_magnetometer = bundle.getBoolean(PreferenceKeys.SupportsMagnetometerKey); + if (!supports_magnetometer) { + CheckBoxPreference magnetPref = (CheckBoxPreference)findPreference(PreferenceKeys.MagnetometerPrefKey); + magnetPref.setChecked(false); + magnetPref.setEnabled(false); + } final boolean supports_auto_stabilise = bundle.getBoolean("supports_auto_stabilise"); if( MyDebug.LOG ) Log.d(TAG, "supports_auto_stabilise: " + supports_auto_stabilise); diff --git a/app/src/main/java/net/sourceforge/opencamera/PreferenceKeys.java b/app/src/main/java/net/sourceforge/opencamera/PreferenceKeys.java index 82e64cb4..1036b04f 100644 --- a/app/src/main/java/net/sourceforge/opencamera/PreferenceKeys.java +++ b/app/src/main/java/net/sourceforge/opencamera/PreferenceKeys.java @@ -311,6 +311,10 @@ public static String getVideoQualityPreferenceKey(int cameraId, boolean high_spe public static final String GyroPreferenceKey = "preference_gyro"; + public static final String MagnetometerPrefKey = "preference_magnetometer"; + + public static final String SupportsMagnetometerKey = "preference_supports_magnetometer"; + public static final String SupportsAccelKey = "supports_accel"; public static final String SupportsGyroKey = "supports_gyro"; 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 b2fa2bb0..463056ca 100644 --- a/app/src/main/java/net/sourceforge/opencamera/sensorlogging/RawSensorInfo.java +++ b/app/src/main/java/net/sourceforge/opencamera/sensorlogging/RawSensorInfo.java @@ -19,43 +19,58 @@ import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; +import java.util.Arrays; +import java.util.Collections; import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * Handles gyroscope and accelerometer raw info recording + * Assumes all the used sensor types are motion or position sensors + * and output [x, y, z] values -- the class should be updated if that changes */ public class RawSensorInfo implements SensorEventListener { private static final String TAG = "RawSensorInfo"; - private static final String SENSOR_TYPE_ACCEL = "accel"; - private static final String SENSOR_TYPE_GYRO = "gyro"; private static final String CSV_SEPARATOR = ","; + private static final List SENSOR_TYPES = Collections.unmodifiableList( + Arrays.asList(Sensor.TYPE_ACCELEROMETER, Sensor.TYPE_GYROSCOPE, Sensor.TYPE_MAGNETIC_FIELD) + ); + private static final Map SENSOR_TYPE_NAMES; + static { + SENSOR_TYPE_NAMES = new HashMap<>(); + SENSOR_TYPE_NAMES.put(Sensor.TYPE_ACCELEROMETER, "accel"); + SENSOR_TYPE_NAMES.put(Sensor.TYPE_GYROSCOPE, "gyro"); + SENSOR_TYPE_NAMES.put(Sensor.TYPE_MAGNETIC_FIELD, "magnetic"); + } final private SensorManager mSensorManager; - final private Sensor mSensorGyro; +/* final private Sensor mSensorGyro; final private Sensor mSensorAccel; + final private Sensor mSensorMagnetic; private PrintWriter mGyroBufferedWriter; - private PrintWriter mAccelBufferedWriter; + private PrintWriter mAccelBufferedWriter;*/ private boolean mIsRecording; - + private final Map mUsedSensorMap; + private final Map mSensorWriterMap; public boolean isSensorAvailable(int sensorType) { - if (sensorType == Sensor.TYPE_ACCELEROMETER) { - return mSensorAccel != null; - } else if (sensorType == Sensor.TYPE_GYROSCOPE) { - return mSensorGyro != null; - } else { - if (MyDebug.LOG) { - Log.e(TAG, "Requested unsupported sensor"); - } - throw new IllegalArgumentException(); - } + return mUsedSensorMap.get(sensorType) != null; } public RawSensorInfo(Context context) { mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); - mSensorGyro = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); + mUsedSensorMap = new HashMap<>(); + mSensorWriterMap = new HashMap<>(); + + for (Integer sensorType : SENSOR_TYPES) { + mUsedSensorMap.put(sensorType, mSensorManager.getDefaultSensor(sensorType)); + } +/* mSensorGyro = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); mSensorAccel = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + mSensorMagnetic = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); if (MyDebug.LOG) { Log.d(TAG, "RawSensorInfo"); @@ -65,14 +80,13 @@ public RawSensorInfo(Context context) { if (mSensorAccel == null) { Log.d(TAG, "Accelerometer not available"); } - } + }*/ } public int getSensorMinDelay(int sensorType) { - if (sensorType == Sensor.TYPE_ACCELEROMETER) { - return mSensorAccel.getMinDelay(); - } else if (sensorType == Sensor.TYPE_GYROSCOPE) { - return mSensorGyro.getMinDelay(); + Sensor sensor = mUsedSensorMap.get(sensorType); + if (sensor != null) { + return sensor.getMinDelay(); } else { // Unsupported sensorType if (MyDebug.LOG) { @@ -91,11 +105,22 @@ public void onSensorChanged(SensorEvent event) { } sensorData.append(event.timestamp).append("\n"); - if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER && mAccelBufferedWriter != null) { + Sensor sensor = mUsedSensorMap.get(event.sensor.getType()); + if (sensor != null) { + PrintWriter sensorWriter = mSensorWriterMap.get(event.sensor.getType()); + if (sensorWriter != null) { + sensorWriter.write(sensorData.toString()); + } else { + if (MyDebug.LOG) { + Log.d(TAG, "Sensor writer for the requested type wasn't initialized"); + } + } + } + /*if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER && mAccelBufferedWriter != null) { mAccelBufferedWriter.write(sensorData.toString()); } else if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE && mGyroBufferedWriter != null) { mGyroBufferedWriter.write(sensorData.toString()); - } + }*/ } } @@ -120,10 +145,13 @@ private FileWriter getRawSensorInfoFileWriter(MainActivity mainActivity, String ParcelFileDescriptor rawSensorInfoPfd = mainActivity .getContentResolver() .openFileDescriptor(saveUri, "w"); - fileWriter = new FileWriter(rawSensorInfoPfd.getFileDescriptor()); - File saveFile = storageUtils.getFileFromDocumentUriSAF(saveUri, false); - storageUtils.broadcastFile(saveFile, true, false, true); - + if (rawSensorInfoPfd != null) { + fileWriter = new FileWriter(rawSensorInfoPfd.getFileDescriptor()); + File saveFile = storageUtils.getFileFromDocumentUriSAF(saveUri, false); + storageUtils.broadcastFile(saveFile, true, false, true); + } else { + throw new IOException("File descriptor was null"); + } } else { File saveFile = storageUtils.createOutputCaptureInfoFile( StorageUtils.MEDIA_TYPE_RAW_SENSOR_INFO, sensorType, "csv", lastVideoDate @@ -156,12 +184,16 @@ private PrintWriter setupRawSensorInfoWriter(MainActivity mainActivity, String s } public void startRecording(MainActivity mainActivity, Date currentVideoDate) { - startRecording(mainActivity, currentVideoDate, true, true); + Map wantSensorRecordingMap = new HashMap<>(); + for (Integer sensorType : SENSOR_TYPES) { + wantSensorRecordingMap.put(sensorType, true); + } + startRecording(mainActivity, currentVideoDate, wantSensorRecordingMap); } - public void startRecording(MainActivity mainActivity, Date currentVideoDate, boolean wantGyroRecording, boolean wantAccelRecording) { + public void startRecording(MainActivity mainActivity, Date currentVideoDate, Map wantSensorRecordingMap) { try { - if (wantGyroRecording && mSensorGyro != null) { +/* if (wantGyroRecording && mSensorGyro != null) { mGyroBufferedWriter = setupRawSensorInfoWriter( mainActivity, SENSOR_TYPE_GYRO, currentVideoDate ); @@ -170,6 +202,18 @@ public void startRecording(MainActivity mainActivity, Date currentVideoDate, boo mAccelBufferedWriter = setupRawSensorInfoWriter( mainActivity, SENSOR_TYPE_ACCEL, currentVideoDate ); + }*/ + for (Integer sensorType : wantSensorRecordingMap.keySet()) { + Boolean wantRecording = wantSensorRecordingMap.get(sensorType); + if (sensorType != null && + wantRecording != null && + wantRecording == true + ) { + mSensorWriterMap.put( + sensorType, + setupRawSensorInfoWriter(mainActivity, SENSOR_TYPE_NAMES.get(sensorType), currentVideoDate) + ); + } } mIsRecording = true; } catch (IOException e) { @@ -184,14 +228,19 @@ public void stopRecording() { if (MyDebug.LOG) { Log.d(TAG, "Close all files"); } - if (mGyroBufferedWriter != null) { + for (PrintWriter sensorWriter : mSensorWriterMap.values()) { + if (sensorWriter != null) { + sensorWriter.close(); + } + } + /*if (mGyroBufferedWriter != null) { mGyroBufferedWriter.flush(); mGyroBufferedWriter.close(); } if (mAccelBufferedWriter != null) { mAccelBufferedWriter.flush(); mAccelBufferedWriter.close(); - } + }*/ mIsRecording = false; } @@ -199,12 +248,24 @@ public boolean isRecording() { return mIsRecording; } - public void enableSensors(int accelSampleRate, int gyroSampleRate) { + public void enableSensors(Map sampleRateMap) { if (MyDebug.LOG) { Log.d(TAG, "enableSensors"); } - enableSensor(Sensor.TYPE_GYROSCOPE, gyroSampleRate); - enableSensor(Sensor.TYPE_ACCELEROMETER, accelSampleRate); + for (Integer sensorType : mUsedSensorMap.keySet()) { + Integer sampleRate = sampleRateMap.get(sensorType); + if (sampleRate == null) { + // Assign default value if not provided + sampleRate = 0; + } + + if (sensorType != null) { + enableSensor(sensorType, sampleRate); + } + + } + /*enableSensor(Sensor.TYPE_GYROSCOPE, gyroSampleRate); + enableSensor(Sensor.TYPE_ACCELEROMETER, accelSampleRate);*/ } @@ -217,7 +278,14 @@ public boolean enableSensor(int sensorType, int sampleRate) { Log.d(TAG, "enableSensor"); } - if (sensorType == Sensor.TYPE_ACCELEROMETER) { + Sensor sensor = mUsedSensorMap.get(sensorType); + if (sensor != null) { + mSensorManager.registerListener(this, sensor, sampleRate); + return true; + } else { + return false; + } + /*if (sensorType == Sensor.TYPE_ACCELEROMETER) { if (mSensorAccel == null) return false; mSensorManager.registerListener(this, mSensorAccel, sampleRate); return true; @@ -227,7 +295,7 @@ public boolean enableSensor(int sensorType, int sampleRate) { return true; } else { return false; - } + }*/ } public void disableSensors() { diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index b7beec73..b98b3ab4 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -98,6 +98,12 @@ android:defaultValue="true" /> + + Date: Thu, 28 Jan 2021 11:56:06 +0300 Subject: [PATCH 03/16] Add enabled sensors map; Organize sensor preferences --- .../opencamera/ExtendedAppInterface.java | 20 ++++- .../opencamera/PreferenceKeys.java | 2 + app/src/main/res/xml/preferences.xml | 85 ++++++++++++------- 3 files changed, 72 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java b/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java index be8a4398..a60d28df 100644 --- a/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java +++ b/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java @@ -13,6 +13,8 @@ import net.sourceforge.opencamera.sensorlogging.VideoFrameInfo; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; /** * Extended implementation of ApplicationInterface, adds raw sensor recording layer to the @@ -62,6 +64,10 @@ private boolean getGyroPref() { return mSharedPreferences.getBoolean(PreferenceKeys.GyroPreferenceKey, true); } + private boolean getMagneticPref() { + return mSharedPreferences.getBoolean(PreferenceKeys.MagnetometerPrefKey, true); + } + /** * Retrieves gyroscope and accelerometer sample rate preference and converts it to number */ @@ -106,10 +112,20 @@ public void startingVideo() { // TODO: abort recording? } } + if (getMagneticPref()) { + int magneticSampleRate = getSensorSampleRatePref(PreferenceKeys.MagneticSampleRatePreferenceKey); + if (!mRawSensorInfo.enableSensor(Sensor.TYPE_MAGNETIC_FIELD, magneticSampleRate)) { + mMainActivity.getPreview().showToast(null, "Magnetometer unavailable"); + // TODO: abort recording? + } + } //mRawSensorInfo.startRecording(mMainActivity, mLastVideoDate, get Pref(), getAccelPref()) - // TODO: create map with magnetometer option - mRawSensorInfo.startRecording(mMainActivity, mLastVideoDate); + Map wantSensorRecordingMap = new HashMap<>(); + wantSensorRecordingMap.put(Sensor.TYPE_ACCELEROMETER, getAccelPref()); + wantSensorRecordingMap.put(Sensor.TYPE_GYROSCOPE, getGyroPref()); + wantSensorRecordingMap.put(Sensor.TYPE_MAGNETIC_FIELD, getMagneticPref()); + mRawSensorInfo.startRecording(mMainActivity, mLastVideoDate, wantSensorRecordingMap); // TODO: add message to strings.xml mMainActivity.getPreview().showToast(null, "Starting video with IMU recording"); } catch (NumberFormatException e) { diff --git a/app/src/main/java/net/sourceforge/opencamera/PreferenceKeys.java b/app/src/main/java/net/sourceforge/opencamera/PreferenceKeys.java index 1036b04f..8d1bdcde 100644 --- a/app/src/main/java/net/sourceforge/opencamera/PreferenceKeys.java +++ b/app/src/main/java/net/sourceforge/opencamera/PreferenceKeys.java @@ -325,6 +325,8 @@ public static String getVideoQualityPreferenceKey(int cameraId, boolean high_spe public static final String GyroSampleRatePreferenceKey = "preference_gyro_sample_rate"; + public static final String MagneticSampleRatePreferenceKey = "preference_magnetic_sample_rate"; + public static String getVideoFPSPreferenceKey(int cameraId) { // for cameraId==0, we return preference_video_fps instead of preference_video_fps_0, for // backwards compatibility for people upgrading diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index b98b3ab4..7468fec2 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -86,23 +86,6 @@ android:title="More sensor controls" android:icon="@drawable/ic_more_horiz_white_48dp" android:persistent="false"> - - - - - - + + - + + + + + + + + + + + + + From cfa0e2c0ce7b01e36782e99bfdfb0fbc0203e745 Mon Sep 17 00:00:00 2001 From: Azat Akhmetyanov Date: Thu, 28 Jan 2021 11:57:58 +0300 Subject: [PATCH 04/16] Rm todo --- .../java/net/sourceforge/opencamera/ExtendedAppInterface.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java b/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java index a60d28df..fbd8fd82 100644 --- a/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java +++ b/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java @@ -109,14 +109,12 @@ public void startingVideo() { int gyroSampleRate = getSensorSampleRatePref(PreferenceKeys.GyroSampleRatePreferenceKey); if (!mRawSensorInfo.enableSensor(Sensor.TYPE_GYROSCOPE, gyroSampleRate)) { mMainActivity.getPreview().showToast(null, "Gyroscope unavailable"); - // TODO: abort recording? } } if (getMagneticPref()) { int magneticSampleRate = getSensorSampleRatePref(PreferenceKeys.MagneticSampleRatePreferenceKey); if (!mRawSensorInfo.enableSensor(Sensor.TYPE_MAGNETIC_FIELD, magneticSampleRate)) { mMainActivity.getPreview().showToast(null, "Magnetometer unavailable"); - // TODO: abort recording? } } From 15f66068a858d732fd91c79b35789bed4e27ac02 Mon Sep 17 00:00:00 2001 From: Azat Akhmetyanov Date: Thu, 28 Jan 2021 12:00:51 +0300 Subject: [PATCH 05/16] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3ef96e02..83b8d109 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/MobileRoboticsSkoltech/OpenCamera-Sensors.svg?branch=master)](https://travis-ci.org/MobileRoboticsSkoltech/OpenCamera-Sensors) -OpenCamera Sensors is an Android application for synchronized recording of video and IMU data. It records IMU data and video with frame timestamps synced to the same clock. +OpenCamera Sensors is an Android application for synchronized recording of video and IMU data. It records sensor data (accelerometer, gyroscope, magnetometer) and video with frame timestamps synced to the same clock. 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. @@ -19,9 +19,10 @@ This project is based on [Open Camera](https://opencamera.org.uk/) — a popul - **Record video** - **Get data** from ```DCIM/OpenCamera```: - Video file - - IMU data and frame timestamps in the directory ```{VIDEO_DATE}```: + - Sensor data and frame timestamps in the directory ```{VIDEO_DATE}```: -```{VIDEO_NAME}_gyro.csv```, data format: ```X-data, Y-data, Z-data, timestamp (ns)``` - ```{VIDEO_NAME}_accel.csv```, data format: ```X-data, Y-data, Z-data, timestamp (ns)``` + - ```{VIDEO_NAME}_magnetic.csv```, data format: ```X-data, Y-data, Z-data, timestamp (ns)``` - ```{VIDEO_NAME}_timestamps.csv```, data format: ```timestamp (ns)``` ## Good practices for data recording From 5d9be11f13b39744848a4a3a383cfb2f45632ef4 Mon Sep 17 00:00:00 2001 From: Azat Akhmetyanov Date: Thu, 28 Jan 2021 12:04:51 +0300 Subject: [PATCH 06/16] Update target SDK --- app/build.gradle | 2 +- app/src/main/java/net/sourceforge/opencamera/MainActivity.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index c8fbd211..70b5346f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,7 +11,7 @@ android { defaultConfig { applicationId "com.opencamera_extended.app" minSdkVersion 19 - targetSdkVersion 29 + targetSdkVersion 30 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/main/java/net/sourceforge/opencamera/MainActivity.java b/app/src/main/java/net/sourceforge/opencamera/MainActivity.java index f8bbe3ca..dc7e2c61 100644 --- a/app/src/main/java/net/sourceforge/opencamera/MainActivity.java +++ b/app/src/main/java/net/sourceforge/opencamera/MainActivity.java @@ -715,7 +715,7 @@ public void onInit(int status) { public static boolean useScopedStorage() { //return false; //return true; - return false; + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; } public int getNavigationGap() { From d105b962765f7dd744bbbe53891ccf14cda8242f Mon Sep 17 00:00:00 2001 From: Azat Akhmetyanov Date: Fri, 29 Jan 2021 13:16:03 +0300 Subject: [PATCH 07/16] Create sensor files map --- .../opencamera/ExtendedAppInterface.java | 2 +- .../sensorlogging/RawSensorInfo.java | 21 +++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java b/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java index fbd8fd82..01f2be47 100644 --- a/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java +++ b/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java @@ -37,7 +37,7 @@ public VideoFrameInfo setupFrameInfo() throws IOException { ExtendedAppInterface(MainActivity mainActivity, Bundle savedInstanceState) { super(mainActivity, savedInstanceState); - mRawSensorInfo = new RawSensorInfo(mainActivity); + mRawSensorInfo = mainActivity.getRawSensorInfoManager(); mMainActivity = mainActivity; mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(mainActivity); // We create it only once here (not during the video) as it is a costly operation 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 463056ca..d0e8d7f0 100644 --- a/app/src/main/java/net/sourceforge/opencamera/sensorlogging/RawSensorInfo.java +++ b/app/src/main/java/net/sourceforge/opencamera/sensorlogging/RawSensorInfo.java @@ -55,6 +55,11 @@ public class RawSensorInfo implements SensorEventListener { private boolean mIsRecording; private final Map mUsedSensorMap; private final Map mSensorWriterMap; + private final Map mLastSensorFilesMap; + + public Map getLastSensorFilesMap() { + return mLastSensorFilesMap; + } public boolean isSensorAvailable(int sensorType) { return mUsedSensorMap.get(sensorType) != null; @@ -64,6 +69,7 @@ public RawSensorInfo(Context context) { mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); mUsedSensorMap = new HashMap<>(); mSensorWriterMap = new HashMap<>(); + mLastSensorFilesMap = new HashMap<>(); for (Integer sensorType : SENSOR_TYPES) { mUsedSensorMap.put(sensorType, mSensorManager.getDefaultSensor(sensorType)); @@ -133,14 +139,14 @@ public void onAccuracyChanged(Sensor sensor, int accuracy) { * Handles sensor info file creation, uses StorageUtils to work both with SAF and standard file * access. */ - private FileWriter getRawSensorInfoFileWriter(MainActivity mainActivity, String sensorType, + private FileWriter getRawSensorInfoFileWriter(MainActivity mainActivity, Integer sensorType, String sensorName, Date lastVideoDate) throws IOException { StorageUtilsWrapper storageUtils = mainActivity.getStorageUtils(); FileWriter fileWriter; try { if (storageUtils.isUsingSAF()) { Uri saveUri = storageUtils.createOutputCaptureInfoFileSAF( - StorageUtils.MEDIA_TYPE_RAW_SENSOR_INFO, sensorType, "csv", lastVideoDate + StorageUtils.MEDIA_TYPE_RAW_SENSOR_INFO, sensorName, "csv", lastVideoDate ); ParcelFileDescriptor rawSensorInfoPfd = mainActivity .getContentResolver() @@ -149,17 +155,19 @@ private FileWriter getRawSensorInfoFileWriter(MainActivity mainActivity, String fileWriter = new FileWriter(rawSensorInfoPfd.getFileDescriptor()); File saveFile = storageUtils.getFileFromDocumentUriSAF(saveUri, false); storageUtils.broadcastFile(saveFile, true, false, true); + mLastSensorFilesMap.put(sensorType, saveFile); } else { throw new IOException("File descriptor was null"); } } else { File saveFile = storageUtils.createOutputCaptureInfoFile( - StorageUtils.MEDIA_TYPE_RAW_SENSOR_INFO, sensorType, "csv", lastVideoDate + StorageUtils.MEDIA_TYPE_RAW_SENSOR_INFO, sensorName, "csv", lastVideoDate ); fileWriter = new FileWriter(saveFile); if (MyDebug.LOG) { Log.d(TAG, "save to: " + saveFile.getAbsolutePath()); } + mLastSensorFilesMap.put(sensorType, saveFile); storageUtils.broadcastFile(saveFile, false, false, false); } return fileWriter; @@ -172,10 +180,10 @@ private FileWriter getRawSensorInfoFileWriter(MainActivity mainActivity, String } } - private PrintWriter setupRawSensorInfoWriter(MainActivity mainActivity, String sensorType, + private PrintWriter setupRawSensorInfoWriter(MainActivity mainActivity, Integer sensorType, String sensorName, Date currentVideoDate) throws IOException { FileWriter rawSensorInfoFileWriter = getRawSensorInfoFileWriter( - mainActivity, sensorType, currentVideoDate + mainActivity, sensorType, sensorName, currentVideoDate ); PrintWriter rawSensorInfoWriter = new PrintWriter( new BufferedWriter(rawSensorInfoFileWriter) @@ -192,6 +200,7 @@ public void startRecording(MainActivity mainActivity, Date currentVideoDate) { } public void startRecording(MainActivity mainActivity, Date currentVideoDate, Map wantSensorRecordingMap) { + mLastSensorFilesMap.clear(); try { /* if (wantGyroRecording && mSensorGyro != null) { mGyroBufferedWriter = setupRawSensorInfoWriter( @@ -211,7 +220,7 @@ public void startRecording(MainActivity mainActivity, Date currentVideoDate, Map ) { mSensorWriterMap.put( sensorType, - setupRawSensorInfoWriter(mainActivity, SENSOR_TYPE_NAMES.get(sensorType), currentVideoDate) + setupRawSensorInfoWriter(mainActivity, sensorType, SENSOR_TYPE_NAMES.get(sensorType), currentVideoDate) ); } } From 239e2d14813b99ea23e46c7c019fc0518b0350d3 Mon Sep 17 00:00:00 2001 From: Azat Akhmetyanov Date: Fri, 29 Jan 2021 13:19:55 +0300 Subject: [PATCH 08/16] Update instrumented tests for new sensor setup --- .../opencamera/test/MainActivityTest.java | 53 +++++++++++++++++++ .../opencamera/test/SubsetTests.java | 5 ++ 2 files changed, 58 insertions(+) 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 d2b2ee55..33db1057 100644 --- a/app/src/androidTest/java/net/sourceforge/opencamera/test/MainActivityTest.java +++ b/app/src/androidTest/java/net/sourceforge/opencamera/test/MainActivityTest.java @@ -14,6 +14,7 @@ import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Set; import net.sourceforge.opencamera.LocationSupplier; @@ -47,6 +48,7 @@ import android.graphics.Matrix; import android.graphics.Point; import android.graphics.PointF; +import android.hardware.Sensor; import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.params.TonemapCurve; @@ -7830,6 +7832,57 @@ public void testVideoImuInfo() throws InterruptedException { assertEquals(expectedNFiles + 1, nNewFiles); } + /* Test recording video with all sensors enabled + Assumes all of the sensors are supported + */ + public void testVideoAllSensors() throws InterruptedException { + Log.d(TAG, "testVideoAllSensors"); + // check sensor files + Map sensorFilesMap = subTestVideoSensors(true, true, true); + assertTrue(sensorFilesMap.get(Sensor.TYPE_ACCELEROMETER).canRead()); + assertTrue(sensorFilesMap.get(Sensor.TYPE_GYROSCOPE).canRead()); + assertTrue(sensorFilesMap.get(Sensor.TYPE_MAGNETIC_FIELD).canRead()); + } + + public void testVideoMagnetometer() throws InterruptedException { + Log.d(TAG, "testVideoMagnetometer"); + Map sensorFilesMap = subTestVideoSensors(true, false, false); + assertTrue(sensorFilesMap.get(Sensor.TYPE_MAGNETIC_FIELD).canRead()); + } + + public void testVideoAccel() throws InterruptedException { + Log.d(TAG, "testVideoAccel"); + Map sensorFilesMap = subTestVideoSensors(false, true, false); + assertTrue(sensorFilesMap.get(Sensor.TYPE_ACCELEROMETER).canRead()); + } + + public void testVideoGyro() throws InterruptedException { + Log.d(TAG, "testVideoGyro"); + Map sensorFilesMap = subTestVideoSensors(false, false, true); + assertTrue(sensorFilesMap.get(Sensor.TYPE_GYROSCOPE).canRead()); + } + + public Map subTestVideoSensors(boolean wantMagnetic, boolean wantAccel, boolean wantGyro) throws InterruptedException { + setToDefault(); + SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(mActivity); + SharedPreferences.Editor editor = settings.edit(); + // enable all of the sensors + editor.putBoolean(PreferenceKeys.IMURecordingPreferenceKey, true); + editor.putBoolean(PreferenceKeys.MagnetometerPrefKey, wantMagnetic); + editor.putBoolean(PreferenceKeys.AccelPreferenceKey, wantAccel); + editor.putBoolean(PreferenceKeys.GyroPreferenceKey, wantGyro); + editor.apply(); + updateForSettings(); + + // count initial files in folder + File folder = mActivity.getImageFolder(); + Log.d(TAG, "folder: " + folder); + int expectedNFiles = 1; + int nNewFiles = subTestTakeVideo(false, false, true, false, null, 5000, false, expectedNFiles); + return mActivity.getRawSensorInfoManager() + .getLastSensorFilesMap(); + } + /* Test recording video with raw IMU sensor info */ public void testVideoImuInfoSAF() throws InterruptedException { 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 668593c3..4991fd29 100644 --- a/app/src/androidTest/java/net/sourceforge/opencamera/test/SubsetTests.java +++ b/app/src/androidTest/java/net/sourceforge/opencamera/test/SubsetTests.java @@ -11,6 +11,11 @@ public static Test suite() { TestSuite suite = new TestSuite(MainTests.class.getName()); // Basic video tests suite.addTest(TestSuite.createTest(MainActivityTest.class, "testVideoImuInfo")); + suite.addTest(TestSuite.createTest(MainActivityTest.class, "testVideoAllSensors")); + suite.addTest(TestSuite.createTest(MainActivityTest.class, "testVideoGyro")); + suite.addTest(TestSuite.createTest(MainActivityTest.class, "testVideoAccel")); + suite.addTest(TestSuite.createTest(MainActivityTest.class, "testVideoMagnetometer")); + suite.addTest(TestSuite.createTest(MainActivityTest.class, "testTakeVideo")); // TODO: update this test for new video rec stop logic, now it relies on synchronous recording stop From 3c08d90b5678b99e726bb540bf75f5f4003fdeef Mon Sep 17 00:00:00 2001 From: Azat Akhmetyanov Date: Mon, 1 Feb 2021 10:03:46 +0300 Subject: [PATCH 09/16] [run instrumentation] Improve instrumented tests for the cases when sensor is not supported --- .../opencamera/test/MainActivityTest.java | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) 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 33db1057..6fecdd26 100644 --- a/app/src/androidTest/java/net/sourceforge/opencamera/test/MainActivityTest.java +++ b/app/src/androidTest/java/net/sourceforge/opencamera/test/MainActivityTest.java @@ -32,6 +32,7 @@ import net.sourceforge.opencamera.SaveLocationHistory; import net.sourceforge.opencamera.cameracontroller.CameraController; import net.sourceforge.opencamera.preview.Preview; +import net.sourceforge.opencamera.sensorlogging.RawSensorInfo; import net.sourceforge.opencamera.ui.FolderChooserDialog; import net.sourceforge.opencamera.ui.PopupView; @@ -7839,27 +7840,34 @@ public void testVideoAllSensors() throws InterruptedException { Log.d(TAG, "testVideoAllSensors"); // check sensor files Map sensorFilesMap = subTestVideoSensors(true, true, true); - assertTrue(sensorFilesMap.get(Sensor.TYPE_ACCELEROMETER).canRead()); - assertTrue(sensorFilesMap.get(Sensor.TYPE_GYROSCOPE).canRead()); - assertTrue(sensorFilesMap.get(Sensor.TYPE_MAGNETIC_FIELD).canRead()); + assertSensorRecFileExists(Sensor.TYPE_GYROSCOPE, sensorFilesMap); + assertSensorRecFileExists(Sensor.TYPE_MAGNETIC_FIELD, sensorFilesMap); + assertSensorRecFileExists(Sensor.TYPE_ACCELEROMETER, sensorFilesMap); } public void testVideoMagnetometer() throws InterruptedException { Log.d(TAG, "testVideoMagnetometer"); Map sensorFilesMap = subTestVideoSensors(true, false, false); - assertTrue(sensorFilesMap.get(Sensor.TYPE_MAGNETIC_FIELD).canRead()); + assertSensorRecFileExists(Sensor.TYPE_MAGNETIC_FIELD, sensorFilesMap); } public void testVideoAccel() throws InterruptedException { Log.d(TAG, "testVideoAccel"); Map sensorFilesMap = subTestVideoSensors(false, true, false); - assertTrue(sensorFilesMap.get(Sensor.TYPE_ACCELEROMETER).canRead()); + assertSensorRecFileExists(Sensor.TYPE_ACCELEROMETER, sensorFilesMap); } public void testVideoGyro() throws InterruptedException { Log.d(TAG, "testVideoGyro"); Map sensorFilesMap = subTestVideoSensors(false, false, true); - assertTrue(sensorFilesMap.get(Sensor.TYPE_GYROSCOPE).canRead()); + assertSensorRecFileExists(Sensor.TYPE_GYROSCOPE, sensorFilesMap); + } + + private void assertSensorRecFileExists(Integer sensorType, Map sensorFilesMap) { + assertTrue( + mActivity.getRawSensorInfoManager().isSensorAvailable(sensorType) && + sensorFilesMap.get(sensorType).canRead() + ); } public Map subTestVideoSensors(boolean wantMagnetic, boolean wantAccel, boolean wantGyro) throws InterruptedException { From 1780f7c66bac214bc214abc55b2b66041c9c7c9d Mon Sep 17 00:00:00 2001 From: Azat Akhmetyanov Date: Mon, 1 Feb 2021 12:19:31 +0300 Subject: [PATCH 10/16] [run instrumentation] Fix bug in the check of what sensors are enabled --- .../java/net/sourceforge/opencamera/ExtendedAppInterface.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java b/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java index 01f2be47..4bef3bbb 100644 --- a/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java +++ b/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java @@ -96,7 +96,7 @@ public void startingVideo() { if (MyDebug.LOG) { Log.d(TAG, "starting video"); } - if (getIMURecordingPref() && useCamera2() && (getGyroPref() || getAccelPref())) { + if (getIMURecordingPref() && useCamera2() && (getGyroPref() || getAccelPref() || getMagneticPref())) { // Extracting sample rates from shared preferences try { if (getAccelPref()) { @@ -134,7 +134,7 @@ public void startingVideo() { } } else if (getIMURecordingPref() && !useCamera2()) { mMainActivity.getPreview().showToast(null, "Not using Camera2API! Can't record in sync with IMU"); - } else if (getIMURecordingPref() && !(getGyroPref() || getAccelPref())) { + } else if (getIMURecordingPref() && !(getGyroPref() || getMagneticPref() || getAccelPref())) { mMainActivity.getPreview().showToast(null, "Requested IMU recording but no sensors were enabled"); } super.startingVideo(); From cc6212a4f176b35c1ec6dcfde7395c99beb2278b Mon Sep 17 00:00:00 2001 From: azaat Date: Thu, 11 Mar 2021 22:42:56 +0300 Subject: [PATCH 11/16] Update new sensor rec logic with the changes in master --- app/build.gradle | 2 +- .../opencamera/ExtendedAppInterface.java | 55 ++++++++++--------- .../sourceforge/opencamera/MainActivity.java | 14 +++++ .../sensorremote/RemoteRpcRequestHandler.java | 23 +++++--- .../sensorremote/RemoteRpcServer.java | 5 +- 5 files changed, 63 insertions(+), 36 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 70b5346f..c8fbd211 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java b/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java index 0b7c0f69..c0cebea6 100644 --- a/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java +++ b/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java @@ -12,6 +12,7 @@ import net.sourceforge.opencamera.sensorlogging.VideoPhaseInfo; import java.io.IOException; +import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.concurrent.BlockingQueue; @@ -99,6 +100,34 @@ public boolean getSaveFramesPref() { return mSharedPreferences.getBoolean(PreferenceKeys.saveFramesPreferenceKey, false); } + public void startImu(boolean wantAccel, boolean wantGyro, boolean wantMagnetic, Date currentDate) { + if (wantAccel) { + int accelSampleRate = getSensorSampleRatePref(PreferenceKeys.AccelSampleRatePreferenceKey); + if (!mRawSensorInfo.enableSensor(Sensor.TYPE_ACCELEROMETER, accelSampleRate)) { + mMainActivity.getPreview().showToast(null, "Accelerometer unavailable"); + } + } + if (wantGyro) { + int gyroSampleRate = getSensorSampleRatePref(PreferenceKeys.GyroSampleRatePreferenceKey); + if (!mRawSensorInfo.enableSensor(Sensor.TYPE_GYROSCOPE, gyroSampleRate)) { + mMainActivity.getPreview().showToast(null, "Gyroscope unavailable"); + } + } + if (wantMagnetic) { + int magneticSampleRate = getSensorSampleRatePref(PreferenceKeys.MagneticSampleRatePreferenceKey); + if (!mRawSensorInfo.enableSensor(Sensor.TYPE_MAGNETIC_FIELD, magneticSampleRate)) { + mMainActivity.getPreview().showToast(null, "Magnetometer unavailable"); + } + } + + //mRawSensorInfo.startRecording(mMainActivity, mLastVideoDate, get Pref(), getAccelPref()) + Map wantSensorRecordingMap = new HashMap<>(); + wantSensorRecordingMap.put(Sensor.TYPE_ACCELEROMETER, getAccelPref()); + wantSensorRecordingMap.put(Sensor.TYPE_GYROSCOPE, getGyroPref()); + wantSensorRecordingMap.put(Sensor.TYPE_MAGNETIC_FIELD, getMagneticPref()); + mRawSensorInfo.startRecording(mMainActivity, currentDate, wantSensorRecordingMap); + } + @Override public void startingVideo() { if (MyDebug.LOG) { @@ -107,31 +136,7 @@ public void startingVideo() { if (getIMURecordingPref() && useCamera2() && (getGyroPref() || getAccelPref() || getMagneticPref())) { // Extracting sample rates from shared preferences try { - if (getAccelPref()) { - int accelSampleRate = getSensorSampleRatePref(PreferenceKeys.AccelSampleRatePreferenceKey); - if (!mRawSensorInfo.enableSensor(Sensor.TYPE_ACCELEROMETER, accelSampleRate)) { - mMainActivity.getPreview().showToast(null, "Accelerometer unavailable"); - } - } - if (getGyroPref()) { - int gyroSampleRate = getSensorSampleRatePref(PreferenceKeys.GyroSampleRatePreferenceKey); - if (!mRawSensorInfo.enableSensor(Sensor.TYPE_GYROSCOPE, gyroSampleRate)) { - mMainActivity.getPreview().showToast(null, "Gyroscope unavailable"); - } - } - if (getMagneticPref()) { - int magneticSampleRate = getSensorSampleRatePref(PreferenceKeys.MagneticSampleRatePreferenceKey); - if (!mRawSensorInfo.enableSensor(Sensor.TYPE_MAGNETIC_FIELD, magneticSampleRate)) { - mMainActivity.getPreview().showToast(null, "Magnetometer unavailable"); - } - } - - //mRawSensorInfo.startRecording(mMainActivity, mLastVideoDate, get Pref(), getAccelPref()) - Map wantSensorRecordingMap = new HashMap<>(); - wantSensorRecordingMap.put(Sensor.TYPE_ACCELEROMETER, getAccelPref()); - wantSensorRecordingMap.put(Sensor.TYPE_GYROSCOPE, getGyroPref()); - wantSensorRecordingMap.put(Sensor.TYPE_MAGNETIC_FIELD, getMagneticPref()); - mRawSensorInfo.startRecording(mMainActivity, mLastVideoDate, wantSensorRecordingMap); + startImu(getAccelPref(), getGyroPref(), getMagneticPref(), mLastVideoDate); // TODO: add message to strings.xml mMainActivity.getPreview().showToast(null, "Starting video with IMU recording"); } catch (NumberFormatException e) { diff --git a/app/src/main/java/net/sourceforge/opencamera/MainActivity.java b/app/src/main/java/net/sourceforge/opencamera/MainActivity.java index c6adb287..a15b17b4 100644 --- a/app/src/main/java/net/sourceforge/opencamera/MainActivity.java +++ b/app/src/main/java/net/sourceforge/opencamera/MainActivity.java @@ -69,6 +69,7 @@ import android.widget.ZoomControls; import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.exifinterface.media.ExifInterface; @@ -99,6 +100,8 @@ */ public class MainActivity extends Activity { private static final String TAG = "MainActivity"; + private static final int WRITE_EXTERNAL_STORAGE = 0; + private static final int REQUEST_PERMISSION = 0; private static int activity_count = 0; @@ -211,6 +214,17 @@ public class MainActivity extends Activity { */ @Override protected void onCreate(Bundle savedInstanceState) { + int permissionCheckStorage = ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE); + if (permissionCheckStorage != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions( MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M + && ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, + REQUEST_PERMISSION); + + return; + } this.mRawSensorInfo = new RawSensorInfo(this); if (MyDebug.LOG) { Log.d(TAG, "Created RawSensorInfo object"); 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 d2b8a639..629171d7 100644 --- a/app/src/main/java/net/sourceforge/opencamera/sensorremote/RemoteRpcRequestHandler.java +++ b/app/src/main/java/net/sourceforge/opencamera/sensorremote/RemoteRpcRequestHandler.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.io.PrintStream; import java.util.Date; +import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; @@ -65,7 +66,7 @@ RemoteRpcResponse handleInvalidRequest() { return mResponseBuilder.error("Invalid request", mContext); } - RemoteRpcResponse handleImuRequest(long durationMillis, boolean wantAccel, boolean wantGyro) { + RemoteRpcResponse handleImuRequest(long durationMillis, boolean wantAccel, boolean wantGyro, boolean wantMagnetic) { if (mRawSensorInfo != null && !mRawSensorInfo.isRecording()) { // TODO: custom rates? Callable recStartCallable = () -> { @@ -73,11 +74,11 @@ RemoteRpcResponse handleImuRequest(long durationMillis, boolean wantAccel, boole SharedPreferences.Editor prefEditor = sharedPreferences.edit(); prefEditor.putBoolean(PreferenceKeys.AccelPreferenceKey, wantAccel); prefEditor.putBoolean(PreferenceKeys.GyroPreferenceKey, wantGyro); + prefEditor.putBoolean(PreferenceKeys.MagnetometerPrefKey, wantMagnetic); prefEditor.apply(); - mRawSensorInfo.enableSensors(0, 0); Date currentDate = new Date(); - mRawSensorInfo.startRecording(currentDate); + mContext.getApplicationInterface().startImu(wantAccel, wantGyro, wantMagnetic, currentDate); return null; }; @@ -94,7 +95,6 @@ RemoteRpcResponse handleImuRequest(long durationMillis, boolean wantAccel, boole } try { - // Await recording start FutureTask recStartTask = new FutureTask<>(recStartCallable); mContext.runOnUiThread(recStartTask); @@ -107,14 +107,21 @@ RemoteRpcResponse handleImuRequest(long durationMillis, boolean wantAccel, boole recStopTask.get(); StringBuilder msg = new StringBuilder(); try { - if (wantAccel && mRawSensorInfo.getLastAccelPath() != null) { - File imuFile = new File(mRawSensorInfo.getLastAccelPath()); + Map lastSensorFiles = mRawSensorInfo.getLastSensorFilesMap(); + if (wantAccel && lastSensorFiles.get(Sensor.TYPE_ACCELEROMETER) != null) { + File imuFile = lastSensorFiles.get(Sensor.TYPE_ACCELEROMETER); + msg.append(getSensorData(imuFile)); + msg.append(SENSOR_DATA_END_MARKER); + msg.append("\n"); + } + if (wantGyro && lastSensorFiles.get(Sensor.TYPE_GYROSCOPE) != null) { + File imuFile = lastSensorFiles.get(Sensor.TYPE_GYROSCOPE); msg.append(getSensorData(imuFile)); msg.append(SENSOR_DATA_END_MARKER); msg.append("\n"); } - if (wantGyro && mRawSensorInfo.getLastGyroPath() != null) { - File imuFile = new File(mRawSensorInfo.getLastGyroPath()); + if (wantGyro && lastSensorFiles.get(Sensor.TYPE_MAGNETIC_FIELD) != null) { + File imuFile = lastSensorFiles.get(Sensor.TYPE_MAGNETIC_FIELD); msg.append(getSensorData(imuFile)); msg.append(SENSOR_DATA_END_MARKER); msg.append("\n"); diff --git a/app/src/main/java/net/sourceforge/opencamera/sensorremote/RemoteRpcServer.java b/app/src/main/java/net/sourceforge/opencamera/sensorremote/RemoteRpcServer.java index 2b2bf593..456ae0c7 100644 --- a/app/src/main/java/net/sourceforge/opencamera/sensorremote/RemoteRpcServer.java +++ b/app/src/main/java/net/sourceforge/opencamera/sensorremote/RemoteRpcServer.java @@ -39,7 +39,7 @@ public class RemoteRpcServer extends Thread { private static final String TAG = "RemoteRpcServer"; private static final int SOCKET_WAIT_TIME_MS = 1000; - private static final String IMU_REQUEST_REGEX = "(imu\\?duration=)(\\d+)(&accel=)(\\d)(&gyro=)(\\d)"; + private static final String IMU_REQUEST_REGEX = "(imu\\?duration=)(\\d+)(&accel=)(\\d)(&gyro=)(\\d)(&magnetic=)(\\d)"; private static final Pattern IMU_REQUEST_PATTERN = Pattern.compile(IMU_REQUEST_REGEX); private final Properties mConfig; @@ -76,11 +76,12 @@ private void handleRequest(String msg, PrintStream outputStream, BufferedOutputS long duration = Long.parseLong(imuRequestMatcher.group(2)); boolean wantAccel = Integer.parseInt(imuRequestMatcher.group(4)) == 1; boolean wantGyro = Integer.parseInt(imuRequestMatcher.group(6)) == 1; + boolean wantMagnetic = Integer.parseInt(imuRequestMatcher.group(8)) == 1; if (MyDebug.LOG) { Log.d(TAG, "received IMU control request, duration = " + duration); } - RemoteRpcResponse imuResponse = mRequestHandler.handleImuRequest(duration, wantAccel, wantGyro); + RemoteRpcResponse imuResponse = mRequestHandler.handleImuRequest(duration, wantAccel, wantGyro, wantMagnetic); outputStream.println(imuResponse.toString()); if (MyDebug.LOG) { From 2ee811d2f52ef751e45f3c99cab7bb95b9c9cb01 Mon Sep 17 00:00:00 2001 From: azaat Date: Mon, 15 Mar 2021 12:19:19 +0300 Subject: [PATCH 12/16] Magnetometer patch for remote recording --- api_client/basic_example.py | 11 +++++------ api_client/src/RemoteControl.py | 18 ++++++++++++------ app/build.gradle | 1 + .../sensorremote/RemoteRpcRequestHandler.java | 2 +- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/api_client/basic_example.py b/api_client/basic_example.py index 0b345e0b..0c65fbf0 100644 --- a/api_client/basic_example.py +++ b/api_client/basic_example.py @@ -1,6 +1,5 @@ import time from src.RemoteControl import RemoteControl -import subprocess HOST = '192.168.1.100' # The smartphone's IP address @@ -11,16 +10,16 @@ def main(): remote = RemoteControl(HOST) print("Connected") - 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) + accel_data, gyro_data, magnetic_data = remote.get_imu(10000, True, False, True) + print("Magnetometer data length: %d" % len(magnetic_data)) + with open("magnetic.csv", "w+") as imu_file: + imu_file.writelines(magnetic_data) phase, duration = remote.start_video() print("%d %f" % (phase, duration)) time.sleep(5) remote.stop_video() - + # receives last video (blocks until received) start = time.time() filename = remote.get_video(want_progress_bar=True) diff --git a/api_client/src/RemoteControl.py b/api_client/src/RemoteControl.py index dc2b2734..88d337c3 100644 --- a/api_client/src/RemoteControl.py +++ b/api_client/src/RemoteControl.py @@ -8,7 +8,7 @@ SUPPORTED_SERVER_VERSIONS = [ 'v.0.0' ] - +NUM_SENSORS = 3 class RemoteControl: """ @@ -26,24 +26,27 @@ def __init__(self, hostname): self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.connect((hostname, int(self.props['RPC_PORT']))) - def get_imu(self, duration_ms, want_accel, want_gyro): + def get_imu(self, duration_ms, want_accel, want_gyro, want_magnetic): """ Request IMU data recording :param duration_ms: (int) duration in milliseconds :param want_accel: (boolean) request accelerometer recording :param want_gyro: (boolean) request gyroscope recording - :return: Tuple (accel_data, gyro_data) - csv data strings + :param want_gyro: (boolean) request magnetometer recording + :return: Tuple (accel_data, gyro_data, magnetic_data) - csv data strings If one of the sensors wasn't requested, the corresponding data is None """ accel = int(want_accel) gyro = int(want_gyro) + magnetic = int(want_magnetic) status, socket_file = self._send_and_get_response_status( - 'imu?duration=%d&accel=%d&gyro=%d\n' % (duration_ms, accel, gyro) + 'imu?duration=%d&accel=%d&gyro=%d&magnetic=%d\n' % (duration_ms, accel, gyro, magnetic) ) accel_data = None gyro_data = None + magnetic_data = None - for i in range(2): + for i in range(NUM_SENSORS): # read filename or end marker line = socket_file.readline() msg = line.strip('\n') @@ -62,8 +65,11 @@ def get_imu(self, duration_ms, want_accel, want_gyro): accel_data = data elif msg.endswith("gyro.csv"): gyro_data = data + elif msg.endswith("magnetic.csv"): + magnetic_data = data + socket_file.close() - return accel_data, gyro_data + return accel_data, gyro_data, magnetic_data def start_video(self): """ diff --git a/app/build.gradle b/app/build.gradle index c8fbd211..52bd9002 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,6 +11,7 @@ android { defaultConfig { applicationId "com.opencamera_extended.app" minSdkVersion 19 + // Important! When we decide to change this to 30 or more, we need to add full support for scoped storage targetSdkVersion 29 renderscriptTargetApi 21 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 629171d7..757b782b 100644 --- a/app/src/main/java/net/sourceforge/opencamera/sensorremote/RemoteRpcRequestHandler.java +++ b/app/src/main/java/net/sourceforge/opencamera/sensorremote/RemoteRpcRequestHandler.java @@ -120,7 +120,7 @@ RemoteRpcResponse handleImuRequest(long durationMillis, boolean wantAccel, boole msg.append(SENSOR_DATA_END_MARKER); msg.append("\n"); } - if (wantGyro && lastSensorFiles.get(Sensor.TYPE_MAGNETIC_FIELD) != null) { + if (wantMagnetic && lastSensorFiles.get(Sensor.TYPE_MAGNETIC_FIELD) != null) { File imuFile = lastSensorFiles.get(Sensor.TYPE_MAGNETIC_FIELD); msg.append(getSensorData(imuFile)); msg.append(SENSOR_DATA_END_MARKER); From 369ecb9f71a55cdaf73adb354fcfba1b1f112201 Mon Sep 17 00:00:00 2001 From: azaat Date: Mon, 15 Mar 2021 12:21:34 +0300 Subject: [PATCH 13/16] Minor ui changes for start/stop of recording --- .../opencamera/ExtendedAppInterface.java | 4 +- .../cameracontroller/CameraController2.java | 50 ++++++++------- .../opencamera/preview/Preview.java | 64 ++++++++++--------- .../sensorlogging/VideoFrameInfo.java | 2 + 4 files changed, 66 insertions(+), 54 deletions(-) diff --git a/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java b/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java index c0cebea6..156834de 100644 --- a/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java +++ b/app/src/main/java/net/sourceforge/opencamera/ExtendedAppInterface.java @@ -136,9 +136,9 @@ public void startingVideo() { if (getIMURecordingPref() && useCamera2() && (getGyroPref() || getAccelPref() || getMagneticPref())) { // Extracting sample rates from shared preferences try { + mMainActivity.getPreview().showToast("Starting video with IMU recording...", true); startImu(getAccelPref(), getGyroPref(), getMagneticPref(), mLastVideoDate); // TODO: add message to strings.xml - mMainActivity.getPreview().showToast(null, "Starting video with IMU recording"); } catch (NumberFormatException e) { if (MyDebug.LOG) { Log.e(TAG, "Failed to retrieve the sample rate preference value"); @@ -165,7 +165,7 @@ public void stoppingVideo() { mRawSensorInfo.disableSensors(); // TODO: add message to strings.xml - mMainActivity.getPreview().showToast(null, "Finished video with IMU recording"); + mMainActivity.getPreview().showToast("Stopping video with IMU recording...", true); } super.stoppingVideo(); diff --git a/app/src/main/java/net/sourceforge/opencamera/cameracontroller/CameraController2.java b/app/src/main/java/net/sourceforge/opencamera/cameracontroller/CameraController2.java index bd579259..f8796230 100644 --- a/app/src/main/java/net/sourceforge/opencamera/cameracontroller/CameraController2.java +++ b/app/src/main/java/net/sourceforge/opencamera/cameracontroller/CameraController2.java @@ -1,17 +1,5 @@ package net.sourceforge.opencamera.cameracontroller; -import net.sourceforge.opencamera.MyDebug; -import net.sourceforge.opencamera.preview.VideoProfile; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Queue; - import android.app.Activity; import android.content.Context; import android.graphics.ImageFormat; @@ -36,7 +24,6 @@ import android.hardware.camera2.params.TonemapCurve; import android.location.Location; import android.media.AudioManager; -import androidx.exifinterface.media.ExifInterface; import android.media.Image; import android.media.ImageReader; import android.media.MediaActionSound; @@ -44,8 +31,6 @@ import android.os.Build; import android.os.Handler; import android.os.HandlerThread; -import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; import android.util.Log; import android.util.Pair; import android.util.Range; @@ -55,6 +40,22 @@ import android.view.SurfaceHolder; import android.view.TextureView; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.exifinterface.media.ExifInterface; + +import net.sourceforge.opencamera.MyDebug; +import net.sourceforge.opencamera.preview.VideoProfile; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Queue; + /** Provides support using Android 5's Camera 2 API * android.hardware.camera2.*. */ @@ -5106,8 +5107,15 @@ public void closeVideoRecordingSession() { // onClosed() callback to ensure that // mediaRecorder encodes all the frames // from the capture session - captureSession.close(); - captureSession = null; + synchronized( background_camera_lock ) { + if (captureSession != null) { + Log.d(TAG, "Before captureSession.close()"); + captureSession.close(); + Log.d(TAG, "After captureSession.close()"); + + captureSession = null; + } + } } private List getCaptureSessionOutputSurfaces( @@ -7219,11 +7227,9 @@ private void createVideoFrameImageReader( if (MyDebug.LOG) { Log.d(TAG, "Create video frame image reader for capture session"); } - List yuvSizes = Arrays.asList( - characteristics.get( - CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) - .getOutputSizes(ImageFormat.YUV_420_888) - ); + android.util.Size[] yuvSizes = characteristics.get( + CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) + .getOutputSizes(ImageFormat.YUV_420_888); List controllerSizes = new LinkedList<>(); for (android.util.Size yuvSize : yuvSizes) { controllerSizes.add(new CameraController.Size(yuvSize.getWidth(), yuvSize.getHeight())); 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 6939c5e2..902e7e64 100644 --- a/app/src/main/java/net/sourceforge/opencamera/preview/Preview.java +++ b/app/src/main/java/net/sourceforge/opencamera/preview/Preview.java @@ -962,9 +962,37 @@ private void configureTransform() { cameraSurface.setTransform(matrix); } - private void stopVideoPostPrepare() { - applicationInterface.stoppingVideo(); + private void stopVideoPostPrepare(boolean from_restart) { Log.d(TAG, "Stopping video post prepare"); + + + if( MyDebug.LOG ) + Log.d(TAG, "stopVideo()"); + + applicationInterface.cameraInOperation(false, true); + reconnectCamera(false); // n.b., if something went wrong with video, then we reopen the camera - which may fail (or simply not reopen, e.g., if app is now paused) + + + if( video_recorder == null ) { + // no need to do anything if not recording + // (important to exit, otherwise we'll momentarily switch the take photo icon to video mode in MyApplicationInterface.stoppingVideo() when opening the settings in landscape mode + if( MyDebug.LOG ) + Log.d(TAG, "video wasn't recording anyway"); + return; + } + if( flashVideoTimerTask != null ) { + flashVideoTimerTask.cancel(); + flashVideoTimerTask = null; + } + if( batteryCheckVideoTimerTask != null ) { + batteryCheckVideoTimerTask.cancel(); + batteryCheckVideoTimerTask = null; + } + if( !from_restart ) { + remaining_restart_video = 0; + } + + if( video_recorder != null ) { // check again, just to be safe if( MyDebug.LOG ) Log.d(TAG, "stop video recording"); @@ -1004,40 +1032,16 @@ private void stopVideoPostPrepare() { @TargetApi(Build.VERSION_CODES.LOLLIPOP) public void stopVideo(boolean from_restart) { - camera_controller.closeVideoRecordingSession(); - - if( MyDebug.LOG ) - Log.d(TAG, "stopVideo()"); - - applicationInterface.cameraInOperation(false, true); - reconnectCamera(false); // n.b., if something went wrong with video, then we reopen the camera - which may fail (or simply not reopen, e.g., if app is now paused) - + applicationInterface.stoppingVideo(); - if( video_recorder == null ) { - // no need to do anything if not recording - // (important to exit, otherwise we'll momentarily switch the take photo icon to video mode in MyApplicationInterface.stoppingVideo() when opening the settings in landscape mode - if( MyDebug.LOG ) - Log.d(TAG, "video wasn't recording anyway"); - return; - } - if( flashVideoTimerTask != null ) { - flashVideoTimerTask.cancel(); - flashVideoTimerTask = null; - } - if( batteryCheckVideoTimerTask != null ) { - batteryCheckVideoTimerTask.cancel(); - batteryCheckVideoTimerTask = null; - } - if( !from_restart ) { - remaining_restart_video = 0; - } + camera_controller.closeVideoRecordingSession(); /* If camera2api is not used, we should stop video immediately. Otherwise it is done in callback after captureSession is closed */ if (!usingCamera2API()) { - stopVideoPostPrepare(); + stopVideoPostPrepare(from_restart); } } @@ -5625,7 +5629,7 @@ public void onVideoFrameTimestampAvailable(long timestamp) { @Override public void onVideoCaptureSessionClosed() { - stopVideoPostPrepare(); + stopVideoPostPrepare(false); if (mVideoFrameInfoWriter != null) { mVideoFrameInfoWriter.close(); mVideoFrameInfoWriter = null; 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 5a30584e..99812f2b 100644 --- a/app/src/main/java/net/sourceforge/opencamera/sensorlogging/VideoFrameInfo.java +++ b/app/src/main/java/net/sourceforge/opencamera/sensorlogging/VideoFrameInfo.java @@ -191,7 +191,9 @@ public void close() { try { if (mFrameBufferedWriter != null) { + Log.d(TAG, "Before writer close()"); mFrameBufferedWriter.close(); + Log.d(TAG, "After writer close()"); } } catch (IOException e) { Log.d(TAG, "Exception occurred when attempting to close mFrameBufferedWriter"); From 22d6f66dcbb91fc04cf866298529a2b6fed1faf4 Mon Sep 17 00:00:00 2001 From: azaat Date: Tue, 23 Mar 2021 19:33:23 +0300 Subject: [PATCH 14/16] [run instrumentation] Update magnetometer frequencies, change server version --- README.md | 1 - api_client/basic_example.py | 2 +- api_client/src/RemoteControl.py | 2 +- app/src/main/assets/server_config.properties | 2 +- app/src/main/res/values/arrays.xml | 21 ++++++++++++++++++-- app/src/main/res/xml/preferences.xml | 12 +++++------ 6 files changed, 28 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 8db0abaa..6f5f8ff8 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,6 @@ 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) diff --git a/api_client/basic_example.py b/api_client/basic_example.py index 0c65fbf0..b3589cb2 100644 --- a/api_client/basic_example.py +++ b/api_client/basic_example.py @@ -1,7 +1,7 @@ import time from src.RemoteControl import RemoteControl -HOST = '192.168.1.100' # The smartphone's IP address +HOST = '192.168.1.75' # The smartphone's IP address def main(): diff --git a/api_client/src/RemoteControl.py b/api_client/src/RemoteControl.py index 88d337c3..0fd93a42 100644 --- a/api_client/src/RemoteControl.py +++ b/api_client/src/RemoteControl.py @@ -6,7 +6,7 @@ BUFFER_SIZE = 4096 PROPS_PATH = '../app/src/main/assets/server_config.properties' SUPPORTED_SERVER_VERSIONS = [ - 'v.0.0' + 'v.0.1' ] NUM_SENSORS = 3 diff --git a/app/src/main/assets/server_config.properties b/app/src/main/assets/server_config.properties index 6e5ca917..94ad16ed 100644 --- a/app/src/main/assets/server_config.properties +++ b/app/src/main/assets/server_config.properties @@ -1,5 +1,5 @@ RPC_PORT=6969 -SERVER_VERSION=v.0.0 +SERVER_VERSION=v.0.1 VIDEO_START_REQUEST=video_start VIDEO_STOP_REQUEST=video_stop GET_VIDEO_REQUEST=get_video diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 360359dd..3bb707b1 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -357,7 +357,7 @@ @string/duration_45m @string/duration_1h - + 20000 10000 5000 @@ -365,13 +365,30 @@ 0 - + 50 Hz 100 Hz 200 Hz 500 Hz Maximum possible + + 1000000 + 100000 + 50000 + 20000 + 10000 + 0 + + + + 1 Hz + 10 Hz + 20 Hz + 50 Hz + 100 Hz + Maximum possible + 0 3 diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 673a73d5..aea76ecb 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -132,8 +132,8 @@ android:key="preference_accel_sample_rate" android:title="Accelerometer frequency" android:summary="Accelerometer sampling frequency in Hz" - android:entries="@array/preference_sample_rate_entries" - android:entryValues="@array/preference_sample_rate_values" + android:entries="@array/imu_preference_sample_rate_entries" + android:entryValues="@array/imu_preference_sample_rate_values" android:defaultValue="0" /> @@ -142,8 +142,8 @@ android:title="Gyroscope frequency" android:defaultValue="0" android:summary="Gyroscope sampling frequency in Hz" - android:entries="@array/preference_sample_rate_entries" - android:entryValues="@array/preference_sample_rate_values" + android:entries="@array/imu_preference_sample_rate_entries" + android:entryValues="@array/imu_preference_sample_rate_values" /> From 50ca36af45230582933e7df743041950ca059574 Mon Sep 17 00:00:00 2001 From: azaat Date: Tue, 23 Mar 2021 21:32:27 +0300 Subject: [PATCH 15/16] [run instrumentation] Fix stopVideoPostPrepare --- .../opencamera/preview/Preview.java | 54 +++++++++---------- 1 file changed, 26 insertions(+), 28 deletions(-) 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 902e7e64..1ca31b30 100644 --- a/app/src/main/java/net/sourceforge/opencamera/preview/Preview.java +++ b/app/src/main/java/net/sourceforge/opencamera/preview/Preview.java @@ -965,34 +965,6 @@ private void configureTransform() { private void stopVideoPostPrepare(boolean from_restart) { Log.d(TAG, "Stopping video post prepare"); - - if( MyDebug.LOG ) - Log.d(TAG, "stopVideo()"); - - applicationInterface.cameraInOperation(false, true); - reconnectCamera(false); // n.b., if something went wrong with video, then we reopen the camera - which may fail (or simply not reopen, e.g., if app is now paused) - - - if( video_recorder == null ) { - // no need to do anything if not recording - // (important to exit, otherwise we'll momentarily switch the take photo icon to video mode in MyApplicationInterface.stoppingVideo() when opening the settings in landscape mode - if( MyDebug.LOG ) - Log.d(TAG, "video wasn't recording anyway"); - return; - } - if( flashVideoTimerTask != null ) { - flashVideoTimerTask.cancel(); - flashVideoTimerTask = null; - } - if( batteryCheckVideoTimerTask != null ) { - batteryCheckVideoTimerTask.cancel(); - batteryCheckVideoTimerTask = null; - } - if( !from_restart ) { - remaining_restart_video = 0; - } - - if( video_recorder != null ) { // check again, just to be safe if( MyDebug.LOG ) Log.d(TAG, "stop video recording"); @@ -1033,6 +1005,32 @@ private void stopVideoPostPrepare(boolean from_restart) { @TargetApi(Build.VERSION_CODES.LOLLIPOP) public void stopVideo(boolean from_restart) { applicationInterface.stoppingVideo(); + if( MyDebug.LOG ) + Log.d(TAG, "stopVideo()"); + + applicationInterface.cameraInOperation(false, true); + reconnectCamera(false); // n.b., if something went wrong with video, then we reopen the camera - which may fail (or simply not reopen, e.g., if app is now paused) + + + if( video_recorder == null ) { + // no need to do anything if not recording + // (important to exit, otherwise we'll momentarily switch the take photo icon to video mode in MyApplicationInterface.stoppingVideo() when opening the settings in landscape mode + if( MyDebug.LOG ) + Log.d(TAG, "video wasn't recording anyway"); + return; + } + if( flashVideoTimerTask != null ) { + flashVideoTimerTask.cancel(); + flashVideoTimerTask = null; + } + if( batteryCheckVideoTimerTask != null ) { + batteryCheckVideoTimerTask.cancel(); + batteryCheckVideoTimerTask = null; + } + if( !from_restart ) { + remaining_restart_video = 0; + } + camera_controller.closeVideoRecordingSession(); From 8a5cbf6024942739386e65cc6a1ea905df9bfd6e Mon Sep 17 00:00:00 2001 From: azaat Date: Wed, 24 Mar 2021 13:28:48 +0300 Subject: [PATCH 16/16] [run instrumentation] Change where stoppingVideo is called --- .../java/net/sourceforge/opencamera/preview/Preview.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 1ca31b30..42acb8ed 100644 --- a/app/src/main/java/net/sourceforge/opencamera/preview/Preview.java +++ b/app/src/main/java/net/sourceforge/opencamera/preview/Preview.java @@ -963,6 +963,7 @@ private void configureTransform() { } private void stopVideoPostPrepare(boolean from_restart) { + applicationInterface.stoppingVideo(); Log.d(TAG, "Stopping video post prepare"); if( video_recorder != null ) { // check again, just to be safe @@ -1004,7 +1005,7 @@ private void stopVideoPostPrepare(boolean from_restart) { @TargetApi(Build.VERSION_CODES.LOLLIPOP) public void stopVideo(boolean from_restart) { - applicationInterface.stoppingVideo(); + camera_controller.closeVideoRecordingSession(); if( MyDebug.LOG ) Log.d(TAG, "stopVideo()"); @@ -1032,8 +1033,6 @@ public void stopVideo(boolean from_restart) { } - camera_controller.closeVideoRecordingSession(); - /* If camera2api is not used, we should stop video immediately. Otherwise it is done in callback after captureSession is closed