diff --git a/_docs/history.html b/_docs/history.html index 9fd649b2..f7db3e4c 100644 --- a/_docs/history.html +++ b/_docs/history.html @@ -61,6 +61,7 @@ FIXED Long pressing on the shutter button in video mode meant nothing happened ADDED Camera vendor extensions show percentage progress on supported Android 14 devices. ADDED Long press on switch camera icons now bring up a menu to jump to any camera (for devices that expose multiple cameras). +UPDATED Smoother zoom for Camera2 API. UPDATED Improvements for loading thumbnails for gallery icon (including fixing orientation for X-NIGHT portrait images on Pixel 6 Pro). UPDATED Improvements for popup menu and exposure UI when using large font sizes. diff --git a/app/src/main/java/net/sourceforge/opencamera/MainActivity.java b/app/src/main/java/net/sourceforge/opencamera/MainActivity.java index 753e6f34..7ab25366 100644 --- a/app/src/main/java/net/sourceforge/opencamera/MainActivity.java +++ b/app/src/main/java/net/sourceforge/opencamera/MainActivity.java @@ -5479,7 +5479,9 @@ public class MainActivity extends AppCompatActivity implements PreferenceFragmen Log.d(TAG, "zoom onProgressChanged: " + progress); // note we zoom even if !fromUser, as various other UI controls (multitouch, volume key zoom, -/+ zoomcontrol) // indirectly set zoom via this method, from setting the zoom slider - preview.zoomTo(preview.getMaxZoom() - progress); + // if hasSmoothZoom()==true, then the preview already handled zooming to the current value + if( !preview.hasSmoothZoom() ) + preview.zoomTo(preview.getMaxZoom() - progress, false); } @Override diff --git a/app/src/main/java/net/sourceforge/opencamera/cameracontroller/CameraController.java b/app/src/main/java/net/sourceforge/opencamera/cameracontroller/CameraController.java index f746cf8e..301f49d9 100644 --- a/app/src/main/java/net/sourceforge/opencamera/cameracontroller/CameraController.java +++ b/app/src/main/java/net/sourceforge/opencamera/cameracontroller/CameraController.java @@ -60,7 +60,7 @@ public abstract class CameraController { public static class CameraFeatures { public boolean is_zoom_supported; public int max_zoom; - public List zoom_ratios; + public List zoom_ratios; // list of supported zoom ratios; each value is the zoom multiplied by 100 public boolean supports_face_detection; public List picture_sizes; public List video_sizes; @@ -541,8 +541,25 @@ public abstract class CameraController { public abstract TonemapProfile getTonemapProfile(); public abstract int getJpegQuality(); public abstract void setJpegQuality(int quality); + /** Returns the current zoom. The returned value is an index into the CameraFeatures.zoom_ratios + * array. + */ public abstract int getZoom(); + /** Set the zoom. + * @param value The index into the CameraFeatures.zoom_ratios array. + */ public abstract void setZoom(int value); + /** Set the zoom. Unlike setZoom(value), this allows specifying any zoom level within the + * supported range. + * @param value The index into the CameraFeatures.zoom_ratios array. + * @param smooth_zoom The desired zoom. With CameraController1 (old Camera API), this is ignored. + * With CameraController2 (Camera2 API), this is used instead of the zoom_ratios + * value. Note that getZoom() will return the value passed to this method, so + * passing an appropriate value (e.g., whatever zoom_ratio is closest to the + * smooth_zoom) is still useful if you want to make use of getZoom(). + * smooth_zoom must still be within the supported range of zoom values. + */ + public abstract void setZoom(int value, float smooth_zoom); public abstract void resetZoom(); // resets to zoom 1x public abstract int getExposureCompensation(); public abstract boolean setExposureCompensation(int new_exposure); diff --git a/app/src/main/java/net/sourceforge/opencamera/cameracontroller/CameraController1.java b/app/src/main/java/net/sourceforge/opencamera/cameracontroller/CameraController1.java index 9a1ff0df..3e573d21 100644 --- a/app/src/main/java/net/sourceforge/opencamera/cameracontroller/CameraController1.java +++ b/app/src/main/java/net/sourceforge/opencamera/cameracontroller/CameraController1.java @@ -963,6 +963,11 @@ public class CameraController1 extends CameraController { } } + @Override + public void setZoom(int value, float smooth_zoom) { + setZoom(value); + } + @Override public void resetZoom() { setZoom(0); 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 c18d05ab..97c91177 100644 --- a/app/src/main/java/net/sourceforge/opencamera/cameracontroller/CameraController2.java +++ b/app/src/main/java/net/sourceforge/opencamera/cameracontroller/CameraController2.java @@ -2514,12 +2514,12 @@ public class CameraController2 extends CameraController { int zoom_value_1x; // prepare zoom rations > 1x - // set 20 steps per 2x factor - final double scale_factor_c = 1.0352649238413775043477881942112; + // set 40 steps per 2x factor + final double scale_factor_c = 1.0174796921026863936352862847966; List zoom_ratios_above_one = new ArrayList<>(); double zoom = scale_factor_c; while( zoom < max_zoom - 1.0e-5f ) { - int zoom_ratio = (int)(zoom*100); + int zoom_ratio = (int)(zoom*100+1.0e-5); zoom_ratios_above_one.add(zoom_ratio); zoom *= scale_factor_c; } @@ -4801,6 +4801,11 @@ public class CameraController2 extends CameraController { @Override public void setZoom(int value) { + setZoom(value, -1.0f); + } + + @Override + public void setZoom(int value, float smooth_zoom) { if( zoom_ratios == null ) { if( MyDebug.LOG ) Log.d(TAG, "zoom not supported"); @@ -4821,7 +4826,21 @@ public class CameraController2 extends CameraController { Log.e(TAG, "invalid zoom value" + value); throw new RuntimeException(); // throw as RuntimeException, as this is a programming error } - float zoom = zoom_ratios.get(value)/100.0f; + if( smooth_zoom > 0.0f ) { + if( smooth_zoom < zoom_ratios.get(0)/100.0f ) { + if( MyDebug.LOG ) + Log.e(TAG, "invalid smooth_zoom: " + smooth_zoom); + throw new RuntimeException("smooth_zoom too small"); + } + else if( smooth_zoom > zoom_ratios.get(zoom_ratios.size()-1)/100.0f ) { + if( MyDebug.LOG ) + Log.e(TAG, "invalid smooth_zoom: " + smooth_zoom); + throw new RuntimeException("smooth_zoom too large"); + } + } + float zoom = smooth_zoom > 0.0f ? smooth_zoom : zoom_ratios.get(value)/100.0f; + if( MyDebug.LOG ) + Log.d(TAG, "zoom to: " + zoom); if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.R ) { camera_settings.has_control_zoom_ratio = true; 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 15610f0b..0dc85ba6 100644 --- a/app/src/main/java/net/sourceforge/opencamera/preview/Preview.java +++ b/app/src/main/java/net/sourceforge/opencamera/preview/Preview.java @@ -761,6 +761,13 @@ public class Preview implements SurfaceHolder.Callback, TextureView.SurfaceTextu private boolean has_smooth_zoom = false; private float smooth_zoom = 1.0f; + /** Returns true if the user is currently pinch zooming, and the Preview has already handled setting + * the zoom via Preview.zoomTo(). + */ + public boolean hasSmoothZoom() { + return this.has_smooth_zoom; + } + /** Handle multitouch zoom. */ private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @@ -821,7 +828,7 @@ public class Preview implements SurfaceHolder.Callback, TextureView.SurfaceTextu if( MyDebug.LOG ) Log.d(TAG, "snapped pinch zoom to 1x zoom"); int snapped_zoom = find1xZoom(); - zoomTo(snapped_zoom); + zoomTo(snapped_zoom, false); } } } @@ -2208,7 +2215,7 @@ public class Preview implements SurfaceHolder.Callback, TextureView.SurfaceTextu if( zoom_pref == -1 ) { zoom_pref = find1xZoom(); } - zoomTo(zoom_pref); + zoomTo(zoom_pref, false); if( MyDebug.LOG ) { Log.d(TAG, "setupCamera: total time after zoomTo: " + (System.currentTimeMillis() - debug_time)); } @@ -4303,7 +4310,9 @@ public class Preview implements SurfaceHolder.Callback, TextureView.SurfaceTextu Log.d(TAG, "scaleZoom() " + scale_factor); if( this.camera_controller != null && this.has_zoom ) { int new_zoom_factor = getScaledZoomFactor(scale_factor); - // n.b., don't call zoomTo; this should be called indirectly by applicationInterface.multitouchZoom() + if( has_smooth_zoom ) + zoomTo(new_zoom_factor, true); + // else don't call zoomTo; this should be called indirectly by applicationInterface.multitouchZoom() applicationInterface.multitouchZoom(new_zoom_factor); } } @@ -4311,7 +4320,7 @@ public class Preview implements SurfaceHolder.Callback, TextureView.SurfaceTextu /** Zooms to the supplied index (within the zoom_ratios array). * @param new_zoom_factor The index to zoom to. */ - public void zoomTo(int new_zoom_factor) { + public void zoomTo(int new_zoom_factor, boolean allow_smooth_zoom) { if( MyDebug.LOG ) Log.d(TAG, "ZoomTo(): " + new_zoom_factor); if( new_zoom_factor < 0 ) @@ -4322,7 +4331,9 @@ public class Preview implements SurfaceHolder.Callback, TextureView.SurfaceTextu if( camera_controller != null ) { if( this.has_zoom ) { // don't cancelAutoFocus() here, otherwise we get sluggish zoom behaviour on Camera2 API - camera_controller.setZoom(new_zoom_factor); + // if pinch zooming, pass through the "smooth" zoom factor so for Camera2 API we get perfectly smooth zoom, rather than it + // being snapped to the discrete zoom values + camera_controller.setZoom(new_zoom_factor, (allow_smooth_zoom && has_smooth_zoom) ? smooth_zoom : -1.0f); applicationInterface.setZoomPref(new_zoom_factor); clearFocusAreas(); }