Loading _docs/history.html +4 −0 Original line number Diff line number Diff line Loading @@ -70,6 +70,10 @@ UPDATED Improvements for loading thumbnails for gallery icon (including fixing o UPDATED Improvements for popup menu and exposure UI when using large font sizes. UPDATED Made user's font size preference apply to on-screen text. UPDATED Changes in preparation for back button behaviour for future Android versions. UPDATED Better compatibility when debug option Settings/Photo settings/"Enable fast HDR/expo burst" is disabled: also change the preview exposure. Turning this option of fixes HDR/expo for Samsung Galaxy devices. New installs on Samsung Galaxy devices now disable fast HDR/expo burst by default. Version 1.52 (2023/08/13) Loading app/src/main/java/net/sourceforge/opencamera/MainActivity.java +12 −2 Original line number Diff line number Diff line Loading @@ -1036,6 +1036,8 @@ public class MainActivity extends AppCompatActivity { if( MyDebug.LOG ) Log.d(TAG, "setDeviceDefaults"); final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); boolean is_samsung = Build.MANUFACTURER.toLowerCase(Locale.US).contains("samsung"); //SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); //boolean is_samsung = Build.MANUFACTURER.toLowerCase(Locale.US).contains("samsung"); //boolean is_oneplus = Build.MANUFACTURER.toLowerCase(Locale.US).contains("oneplus"); //boolean is_nexus = Build.MODEL.toLowerCase(Locale.US).contains("nexus"); Loading Loading @@ -1075,9 +1077,18 @@ public class MainActivity extends AppCompatActivity { if( MyDebug.LOG ) Log.d(TAG, "disable fast burst for camera2"); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putBoolean(PreferenceKeys.getCamera2FastBurstPreferenceKey(), false); editor.putBoolean(PreferenceKeys.Camera2FastBurstPreferenceKey, false); editor.apply(); }*/ if( is_samsung && !is_test ) { // Samsung Galaxy devices (including S10e, S24) have problems with HDR/expo - base images come out with wrong exposures. // This can be fixed by not using fast bast, allowing us to adjust the preview exposure to match. if( MyDebug.LOG ) Log.d(TAG, "disable fast burst for camera2"); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putBoolean(PreferenceKeys.Camera2FastBurstPreferenceKey, false); editor.apply(); } if( supports_camera2 && !is_test ) { // n.b., when testing, we explicitly decide whether to run with Camera2 API or not CameraControllerManager2 manager2 = new CameraControllerManager2(this); Loading @@ -1095,7 +1106,6 @@ public class MainActivity extends AppCompatActivity { boolean default_to_camera2 = false; boolean is_google = Build.MANUFACTURER.toLowerCase(Locale.US).contains("google"); boolean is_nokia = Build.MANUFACTURER.toLowerCase(Locale.US).contains("hmd global"); boolean is_samsung = Build.MANUFACTURER.toLowerCase(Locale.US).contains("samsung"); if( is_google && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ) default_to_camera2 = true; else if( is_nokia && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ) Loading app/src/main/java/net/sourceforge/opencamera/cameracontroller/CameraController2.java +120 −43 Original line number Diff line number Diff line Loading @@ -1473,6 +1473,57 @@ public class CameraController2 extends CameraController { return value; } /** Issues the next slow burst capture, on a post delayed on the handler. */ private void postNextSlowBurst() { if( MyDebug.LOG ) Log.d(TAG, "postNextSlowBurst"); handler.postDelayed(new Runnable() { @Override public void run() { if( MyDebug.LOG ) Log.d(TAG, "take picture after delay for next slow burst"); if( camera != null && hasCaptureSession() ) { // make sure camera wasn't released in the meantime // check for imageQueueWouldBlock needed for focus bracketing if( picture_cb.imageQueueWouldBlock(imageReaderRaw != null ? 1 : 0, 1) ) { if( MyDebug.LOG ) { Log.d(TAG, "...but wait for next bracket, as image queue would block"); } handler.postDelayed(this, 100); //throw new RuntimeException(); // test } else { if( burst_type == BurstType.BURSTTYPE_FOCUS ) { // For focus bracketing mode, we play the shutter sound per shot (so the user can tell when the sequence is complete). // From a user mode, the gap between shots in focus bracketing mode makes this more analogous to the auto-repeat mode // (at the Preview level), which makes the shutter sound per shot. playSound(MediaActionSound.SHUTTER_CLICK); } try { captureSession.capture(slow_burst_capture_requests.get(n_burst_taken), previewCaptureCallback, handler); } catch(CameraAccessException e) { if( MyDebug.LOG ) { Log.e(TAG, "failed to take next focus bracket"); Log.e(TAG, "reason: " + e.getReason()); Log.e(TAG, "message: " + e.getMessage()); } e.printStackTrace(); jpeg_todo = false; raw_todo = false; picture_cb = null; if( take_picture_error_cb != null ) { take_picture_error_cb.onError(); take_picture_error_cb = null; } } } } } }, 500); } private class OnImageAvailableListener implements ImageReader.OnImageAvailableListener { private boolean skip_next_image = false; // whether to ignore the next image (used for dummy_capture_hack) Loading Loading @@ -1616,7 +1667,7 @@ public class CameraController2 extends CameraController { Log.d(TAG, "time since start: " + (System.currentTimeMillis() - slow_burst_start_ms)); } if( burst_type != BurstType.BURSTTYPE_FOCUS ) { try { /*try { if( camera != null && hasCaptureSession() ) { // make sure camera wasn't released in the meantime captureSession.capture(slow_burst_capture_requests.get(n_burst_taken), previewCaptureCallback, handler); } Loading @@ -1632,6 +1683,32 @@ public class CameraController2 extends CameraController { raw_todo = false; picture_cb = null; push_take_picture_error_cb = take_picture_error_cb; }*/ // see note in takePictureBurstBracketing() for why we also set preview for slow burst with expo bracketing - // helps Samsung Galaxy devices if( previewBuilder != null ) { // make sure camera wasn't released in the meantime try { long exposure_time = slow_burst_capture_requests.get(n_burst_taken).get(CaptureRequest.SENSOR_EXPOSURE_TIME); if( MyDebug.LOG ) { Log.d(TAG, "prepare preview for next exposure: " + exposure_time); } previewBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, exposure_time); setRepeatingRequest(previewBuilder.build()); } catch(CameraAccessException e) { if( MyDebug.LOG ) { Log.e(TAG, "failed to take set exposure for next expo bracketing burst"); Log.e(TAG, "reason: " + e.getReason()); Log.e(TAG, "message: " + e.getMessage()); } e.printStackTrace(); jpeg_todo = false; raw_todo = false; picture_cb = null; push_take_picture_error_cb = take_picture_error_cb; } postNextSlowBurst(); } } else if( previewBuilder != null ) { // make sure camera wasn't released in the meantime Loading Loading @@ -1695,47 +1772,7 @@ public class CameraController2 extends CameraController { picture_cb = null; push_take_picture_error_cb = take_picture_error_cb; } handler.postDelayed(new Runnable(){ @Override public void run(){ if( MyDebug.LOG ) Log.d(TAG, "take picture after delay for next focus bracket"); if( camera != null && hasCaptureSession() ) { // make sure camera wasn't released in the meantime if( picture_cb.imageQueueWouldBlock(imageReaderRaw != null ? 1 : 0, 1) ) { if( MyDebug.LOG ) { Log.d(TAG, "...but wait for next focus bracket, as image queue would block"); } handler.postDelayed(this, 100); //throw new RuntimeException(); // test } else { // For focus bracketing mode, we play the shutter sound per shot (so the user can tell when the sequence is complete). // From a user mode, the gap between shots in focus bracketing mode makes this more analogous to the auto-repeat mode // (at the Preview level), which makes the shutter sound per shot. playSound(MediaActionSound.SHUTTER_CLICK); try { captureSession.capture(slow_burst_capture_requests.get(n_burst_taken), previewCaptureCallback, handler); } catch(CameraAccessException e) { if( MyDebug.LOG ) { Log.e(TAG, "failed to take next focus bracket"); Log.e(TAG, "reason: " + e.getReason()); Log.e(TAG, "message: " + e.getMessage()); } e.printStackTrace(); jpeg_todo = false; raw_todo = false; picture_cb = null; if( take_picture_error_cb != null ) { take_picture_error_cb.onError(); take_picture_error_cb = null; } } } } } }, 500); postNextSlowBurst(); } } } Loading Loading @@ -7151,8 +7188,45 @@ public class CameraController2 extends CameraController { Log.d(TAG, "using slow burst"); slow_burst_capture_requests = requests; slow_burst_start_ms = System.currentTimeMillis(); if( burst_type == BurstType.BURSTTYPE_EXPO ) { // Set preview to match - some devices (e.g. Samsung Galaxy) don't produce photos with correct exposure if // the exposure is set to a different value than the preview. // Although we don't/can't do this for fast burst, doing so here means such devices can use HDR/expo when // using use_expo_fast_burst==false. try { previewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_OFF); previewBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, slow_burst_capture_requests.get(n_burst_taken).get(CaptureRequest.SENSOR_SENSITIVITY)); previewBuilder.set(CaptureRequest.SENSOR_FRAME_DURATION, slow_burst_capture_requests.get(n_burst_taken).get(CaptureRequest.SENSOR_FRAME_DURATION)); long exposure_time = slow_burst_capture_requests.get(n_burst_taken).get(CaptureRequest.SENSOR_EXPOSURE_TIME); if( MyDebug.LOG ) { Log.d(TAG, "prepare preview for next exposure: " + exposure_time); } previewBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, exposure_time); setRepeatingRequest(previewBuilder.build()); } catch(CameraAccessException e) { if( MyDebug.LOG ) { Log.e(TAG, "failed to take set exposure for next expo bracketing burst"); Log.e(TAG, "reason: " + e.getReason()); Log.e(TAG, "message: " + e.getMessage()); } e.printStackTrace(); jpeg_todo = false; raw_todo = false; picture_cb = null; push_take_picture_error_cb = take_picture_error_cb; } postNextSlowBurst(); } else { // no need to set preview for first focus bracketing shot, the first focus bracketing always // has same focus distance as preview captureSession.capture(requests.get(0), previewCaptureCallback, handler); } } playSound(MediaActionSound.SHUTTER_CLICK); // play shutter sound asap, otherwise user has the illusion of being slow to take photos } Loading Loading @@ -8896,6 +8970,9 @@ public class CameraController2 extends CameraController { // actual parsing of image data is done in the imageReader's OnImageAvailableListener() // need to cancel the autofocus, and restart the preview after taking the photo // Camera2Basic does a capture then sets a repeating request - do the same here just to be safe // update: this is also important when we do an expo burst (BURSTTYPE_EXPO) with option // use_expo_fast_burst==false, since that changes the exposure of the preview, so we need to // reset it here if( previewBuilder != null ) { previewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL); if( MyDebug.LOG ) Loading Loading
_docs/history.html +4 −0 Original line number Diff line number Diff line Loading @@ -70,6 +70,10 @@ UPDATED Improvements for loading thumbnails for gallery icon (including fixing o UPDATED Improvements for popup menu and exposure UI when using large font sizes. UPDATED Made user's font size preference apply to on-screen text. UPDATED Changes in preparation for back button behaviour for future Android versions. UPDATED Better compatibility when debug option Settings/Photo settings/"Enable fast HDR/expo burst" is disabled: also change the preview exposure. Turning this option of fixes HDR/expo for Samsung Galaxy devices. New installs on Samsung Galaxy devices now disable fast HDR/expo burst by default. Version 1.52 (2023/08/13) Loading
app/src/main/java/net/sourceforge/opencamera/MainActivity.java +12 −2 Original line number Diff line number Diff line Loading @@ -1036,6 +1036,8 @@ public class MainActivity extends AppCompatActivity { if( MyDebug.LOG ) Log.d(TAG, "setDeviceDefaults"); final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); boolean is_samsung = Build.MANUFACTURER.toLowerCase(Locale.US).contains("samsung"); //SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); //boolean is_samsung = Build.MANUFACTURER.toLowerCase(Locale.US).contains("samsung"); //boolean is_oneplus = Build.MANUFACTURER.toLowerCase(Locale.US).contains("oneplus"); //boolean is_nexus = Build.MODEL.toLowerCase(Locale.US).contains("nexus"); Loading Loading @@ -1075,9 +1077,18 @@ public class MainActivity extends AppCompatActivity { if( MyDebug.LOG ) Log.d(TAG, "disable fast burst for camera2"); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putBoolean(PreferenceKeys.getCamera2FastBurstPreferenceKey(), false); editor.putBoolean(PreferenceKeys.Camera2FastBurstPreferenceKey, false); editor.apply(); }*/ if( is_samsung && !is_test ) { // Samsung Galaxy devices (including S10e, S24) have problems with HDR/expo - base images come out with wrong exposures. // This can be fixed by not using fast bast, allowing us to adjust the preview exposure to match. if( MyDebug.LOG ) Log.d(TAG, "disable fast burst for camera2"); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putBoolean(PreferenceKeys.Camera2FastBurstPreferenceKey, false); editor.apply(); } if( supports_camera2 && !is_test ) { // n.b., when testing, we explicitly decide whether to run with Camera2 API or not CameraControllerManager2 manager2 = new CameraControllerManager2(this); Loading @@ -1095,7 +1106,6 @@ public class MainActivity extends AppCompatActivity { boolean default_to_camera2 = false; boolean is_google = Build.MANUFACTURER.toLowerCase(Locale.US).contains("google"); boolean is_nokia = Build.MANUFACTURER.toLowerCase(Locale.US).contains("hmd global"); boolean is_samsung = Build.MANUFACTURER.toLowerCase(Locale.US).contains("samsung"); if( is_google && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ) default_to_camera2 = true; else if( is_nokia && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ) Loading
app/src/main/java/net/sourceforge/opencamera/cameracontroller/CameraController2.java +120 −43 Original line number Diff line number Diff line Loading @@ -1473,6 +1473,57 @@ public class CameraController2 extends CameraController { return value; } /** Issues the next slow burst capture, on a post delayed on the handler. */ private void postNextSlowBurst() { if( MyDebug.LOG ) Log.d(TAG, "postNextSlowBurst"); handler.postDelayed(new Runnable() { @Override public void run() { if( MyDebug.LOG ) Log.d(TAG, "take picture after delay for next slow burst"); if( camera != null && hasCaptureSession() ) { // make sure camera wasn't released in the meantime // check for imageQueueWouldBlock needed for focus bracketing if( picture_cb.imageQueueWouldBlock(imageReaderRaw != null ? 1 : 0, 1) ) { if( MyDebug.LOG ) { Log.d(TAG, "...but wait for next bracket, as image queue would block"); } handler.postDelayed(this, 100); //throw new RuntimeException(); // test } else { if( burst_type == BurstType.BURSTTYPE_FOCUS ) { // For focus bracketing mode, we play the shutter sound per shot (so the user can tell when the sequence is complete). // From a user mode, the gap between shots in focus bracketing mode makes this more analogous to the auto-repeat mode // (at the Preview level), which makes the shutter sound per shot. playSound(MediaActionSound.SHUTTER_CLICK); } try { captureSession.capture(slow_burst_capture_requests.get(n_burst_taken), previewCaptureCallback, handler); } catch(CameraAccessException e) { if( MyDebug.LOG ) { Log.e(TAG, "failed to take next focus bracket"); Log.e(TAG, "reason: " + e.getReason()); Log.e(TAG, "message: " + e.getMessage()); } e.printStackTrace(); jpeg_todo = false; raw_todo = false; picture_cb = null; if( take_picture_error_cb != null ) { take_picture_error_cb.onError(); take_picture_error_cb = null; } } } } } }, 500); } private class OnImageAvailableListener implements ImageReader.OnImageAvailableListener { private boolean skip_next_image = false; // whether to ignore the next image (used for dummy_capture_hack) Loading Loading @@ -1616,7 +1667,7 @@ public class CameraController2 extends CameraController { Log.d(TAG, "time since start: " + (System.currentTimeMillis() - slow_burst_start_ms)); } if( burst_type != BurstType.BURSTTYPE_FOCUS ) { try { /*try { if( camera != null && hasCaptureSession() ) { // make sure camera wasn't released in the meantime captureSession.capture(slow_burst_capture_requests.get(n_burst_taken), previewCaptureCallback, handler); } Loading @@ -1632,6 +1683,32 @@ public class CameraController2 extends CameraController { raw_todo = false; picture_cb = null; push_take_picture_error_cb = take_picture_error_cb; }*/ // see note in takePictureBurstBracketing() for why we also set preview for slow burst with expo bracketing - // helps Samsung Galaxy devices if( previewBuilder != null ) { // make sure camera wasn't released in the meantime try { long exposure_time = slow_burst_capture_requests.get(n_burst_taken).get(CaptureRequest.SENSOR_EXPOSURE_TIME); if( MyDebug.LOG ) { Log.d(TAG, "prepare preview for next exposure: " + exposure_time); } previewBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, exposure_time); setRepeatingRequest(previewBuilder.build()); } catch(CameraAccessException e) { if( MyDebug.LOG ) { Log.e(TAG, "failed to take set exposure for next expo bracketing burst"); Log.e(TAG, "reason: " + e.getReason()); Log.e(TAG, "message: " + e.getMessage()); } e.printStackTrace(); jpeg_todo = false; raw_todo = false; picture_cb = null; push_take_picture_error_cb = take_picture_error_cb; } postNextSlowBurst(); } } else if( previewBuilder != null ) { // make sure camera wasn't released in the meantime Loading Loading @@ -1695,47 +1772,7 @@ public class CameraController2 extends CameraController { picture_cb = null; push_take_picture_error_cb = take_picture_error_cb; } handler.postDelayed(new Runnable(){ @Override public void run(){ if( MyDebug.LOG ) Log.d(TAG, "take picture after delay for next focus bracket"); if( camera != null && hasCaptureSession() ) { // make sure camera wasn't released in the meantime if( picture_cb.imageQueueWouldBlock(imageReaderRaw != null ? 1 : 0, 1) ) { if( MyDebug.LOG ) { Log.d(TAG, "...but wait for next focus bracket, as image queue would block"); } handler.postDelayed(this, 100); //throw new RuntimeException(); // test } else { // For focus bracketing mode, we play the shutter sound per shot (so the user can tell when the sequence is complete). // From a user mode, the gap between shots in focus bracketing mode makes this more analogous to the auto-repeat mode // (at the Preview level), which makes the shutter sound per shot. playSound(MediaActionSound.SHUTTER_CLICK); try { captureSession.capture(slow_burst_capture_requests.get(n_burst_taken), previewCaptureCallback, handler); } catch(CameraAccessException e) { if( MyDebug.LOG ) { Log.e(TAG, "failed to take next focus bracket"); Log.e(TAG, "reason: " + e.getReason()); Log.e(TAG, "message: " + e.getMessage()); } e.printStackTrace(); jpeg_todo = false; raw_todo = false; picture_cb = null; if( take_picture_error_cb != null ) { take_picture_error_cb.onError(); take_picture_error_cb = null; } } } } } }, 500); postNextSlowBurst(); } } } Loading Loading @@ -7151,8 +7188,45 @@ public class CameraController2 extends CameraController { Log.d(TAG, "using slow burst"); slow_burst_capture_requests = requests; slow_burst_start_ms = System.currentTimeMillis(); if( burst_type == BurstType.BURSTTYPE_EXPO ) { // Set preview to match - some devices (e.g. Samsung Galaxy) don't produce photos with correct exposure if // the exposure is set to a different value than the preview. // Although we don't/can't do this for fast burst, doing so here means such devices can use HDR/expo when // using use_expo_fast_burst==false. try { previewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_OFF); previewBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, slow_burst_capture_requests.get(n_burst_taken).get(CaptureRequest.SENSOR_SENSITIVITY)); previewBuilder.set(CaptureRequest.SENSOR_FRAME_DURATION, slow_burst_capture_requests.get(n_burst_taken).get(CaptureRequest.SENSOR_FRAME_DURATION)); long exposure_time = slow_burst_capture_requests.get(n_burst_taken).get(CaptureRequest.SENSOR_EXPOSURE_TIME); if( MyDebug.LOG ) { Log.d(TAG, "prepare preview for next exposure: " + exposure_time); } previewBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, exposure_time); setRepeatingRequest(previewBuilder.build()); } catch(CameraAccessException e) { if( MyDebug.LOG ) { Log.e(TAG, "failed to take set exposure for next expo bracketing burst"); Log.e(TAG, "reason: " + e.getReason()); Log.e(TAG, "message: " + e.getMessage()); } e.printStackTrace(); jpeg_todo = false; raw_todo = false; picture_cb = null; push_take_picture_error_cb = take_picture_error_cb; } postNextSlowBurst(); } else { // no need to set preview for first focus bracketing shot, the first focus bracketing always // has same focus distance as preview captureSession.capture(requests.get(0), previewCaptureCallback, handler); } } playSound(MediaActionSound.SHUTTER_CLICK); // play shutter sound asap, otherwise user has the illusion of being slow to take photos } Loading Loading @@ -8896,6 +8970,9 @@ public class CameraController2 extends CameraController { // actual parsing of image data is done in the imageReader's OnImageAvailableListener() // need to cancel the autofocus, and restart the preview after taking the photo // Camera2Basic does a capture then sets a repeating request - do the same here just to be safe // update: this is also important when we do an expo burst (BURSTTYPE_EXPO) with option // use_expo_fast_burst==false, since that changes the exposure of the preview, so we need to // reset it here if( previewBuilder != null ) { previewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL); if( MyDebug.LOG ) Loading