diff --git a/README.md b/README.md index 1590186c..f00e99a2 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,8 @@ Using CameraView is extremely simple: app:cameraFrameProcessingMaxWidth="@integer/processing_max_width" app:cameraFrameProcessingMaxHeight="@integer/processing_max_height" app:cameraFrameProcessingFormat="@integer/processing_format" + app:cameraFrameProcessingPoolSize="@integer/processing_pool_size" + app:cameraFrameProcessingExecutors="@integer/processing_executors" app:cameraVideoBitRate="@integer/video_bit_rate" app:cameraAudioBitRate="@integer/audio_bit_rate" app:cameraGestureTap="none|autoFocus|takePicture" @@ -146,6 +148,7 @@ Using CameraView is extremely simple: app:cameraPictureMetering="true|false" app:cameraPictureSnapshotMetering="false|true" app:cameraPictureFormat="jpeg|dng" + app:cameraRequestPermissions="true|false" app:cameraExperimental="false|true"> diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java index bbf9d636..5e842f2d 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java @@ -116,12 +116,14 @@ public class CameraView extends FrameLayout implements LifecycleObserver { final static boolean DEFAULT_USE_DEVICE_ORIENTATION = true; final static boolean DEFAULT_PICTURE_METERING = true; final static boolean DEFAULT_PICTURE_SNAPSHOT_METERING = false; + final static boolean DEFAULT_REQUEST_PERMISSIONS = true; final static int DEFAULT_FRAME_PROCESSING_POOL_SIZE = 2; final static int DEFAULT_FRAME_PROCESSING_EXECUTORS = 1; // Self managed parameters private boolean mPlaySounds; private boolean mUseDeviceOrientation; + private boolean mRequestPermissions; private HashMap mGestureMap = new HashMap<>(4); private Preview mPreview; private Engine mEngine; @@ -186,6 +188,8 @@ public class CameraView extends FrameLayout implements LifecycleObserver { boolean useDeviceOrientation = a.getBoolean( R.styleable.CameraView_cameraUseDeviceOrientation, DEFAULT_USE_DEVICE_ORIENTATION); mExperimental = a.getBoolean(R.styleable.CameraView_cameraExperimental, false); + mRequestPermissions = a.getBoolean(R.styleable.CameraView_cameraRequestPermissions, + DEFAULT_REQUEST_PERMISSIONS); mPreview = controls.getPreview(); mEngine = controls.getEngine(); @@ -779,11 +783,14 @@ public class CameraView extends FrameLayout implements LifecycleObserver { needsAudio = needsAudio && c.checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED; - if (needsCamera || needsAudio) { + if (!needsCamera && !needsAudio) { + return true; + } else if (mRequestPermissions) { requestPermissions(needsCamera, needsAudio); return false; + } else { + return false; } - return true; } /** diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java index 02553017..4ae098df 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java @@ -175,12 +175,11 @@ public class Camera1Engine extends CameraBaseEngine implements @Override protected Task onStartBind() { LOG.i("onStartBind:", "Started"); - Object output = mPreview.getOutput(); try { - if (output instanceof SurfaceHolder) { - mCamera.setPreviewDisplay((SurfaceHolder) output); - } else if (output instanceof SurfaceTexture) { - mCamera.setPreviewTexture((SurfaceTexture) output); + if (mPreview.getOutputClass() == SurfaceHolder.class) { + mCamera.setPreviewDisplay((SurfaceHolder) mPreview.getOutput()); + } else if (mPreview.getOutputClass() == SurfaceTexture.class) { + mCamera.setPreviewTexture((SurfaceTexture) mPreview.getOutput()); } else { throw new RuntimeException("Unknown CameraPreview output class."); } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java index a315d9e3..26fe1ff8 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java @@ -480,8 +480,9 @@ public class Camera2Engine extends CameraBaseEngine implements // 1. PREVIEW // Create a preview surface with the correct size. + final Class outputClass = mPreview.getOutputClass(); final Object output = mPreview.getOutput(); - if (output instanceof SurfaceHolder) { + if (outputClass == SurfaceHolder.class) { try { // This must be called from the UI thread... Tasks.await(Tasks.call(new Callable() { @@ -497,7 +498,7 @@ public class Camera2Engine extends CameraBaseEngine implements throw new CameraException(e, CameraException.REASON_FAILED_TO_CONNECT); } mPreviewStreamSurface = ((SurfaceHolder) output).getSurface(); - } else if (output instanceof SurfaceTexture) { + } else if (outputClass == SurfaceTexture.class) { ((SurfaceTexture) output).setDefaultBufferSize( mPreviewStreamSize.getWidth(), mPreviewStreamSize.getHeight()); diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/preview/GlCameraPreview.java b/cameraview/src/main/java/com/otaliastudios/cameraview/preview/GlCameraPreview.java index 361113f1..c678d85b 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/preview/GlCameraPreview.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/preview/GlCameraPreview.java @@ -95,13 +95,13 @@ public class GlCameraPreview extends FilterCameraPreview - + + diff --git a/docs/_config.yml b/docs/_config.yml index ca979b2f..9f9baf72 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -3,7 +3,7 @@ # Source site: http://bruth.github.io/jekyll-docs-template/ # Ref guide: https://visualstudiomagazine.com/Articles/2015/03/01/GitHub-Pages.aspx?Page=2 -title: CameraView v2 +title: CameraView # subtitle is used by ourselves, description is used by seo tag. subtitle: A well documented, high-level Android interface that makes capturing pictures and videos easy, addressing all of the common issues and needs. diff --git a/docs/_layouts/page.html b/docs/_layouts/page.html index db711745..58cb8016 100644 --- a/docs/_layouts/page.html +++ b/docs/_layouts/page.html @@ -4,7 +4,7 @@ layout: default diff --git a/docs/_posts/2018-12-20-changelog.md b/docs/_posts/2018-12-20-changelog.md index 184f7a49..db9a678b 100644 --- a/docs/_posts/2018-12-20-changelog.md +++ b/docs/_posts/2018-12-20-changelog.md @@ -13,13 +13,13 @@ Companies can share a tiny part of their revenue and get private support hours i ## v2.5.0 -- [*Camera2*] New: support for RAW pictures with new APIs `setPictureFormat()` and `CameraOptions.getSupportedPictureFormats()`. Contains a **breaking change**: `PictureResult.getFormat()` is not an integer anymore but rather a `PictureFormat`. This API had no real purpose so this might not affect you ([#691][691]) -- [*Camera2*] New: support for constraining the frame processing size through `setFrameProcessingMaxWidth()` and `setFrameProcessingMaxHeight()`. This can improve processing performance ([#691][691]) -- [*Camera2*] New: support for choosing the frame processing format through `setFrameProcessingFormat()` and `CameraOptions.getSupportedFrameProcessingFormats()` ([#691][691]) -- [*Camera2*] Improvement: Frame processing FPS for Camera2 is now smooth and typically better than Camera1. This required some **breaking changes** (see below) ([#691][691]) -- [*Camera1, Camera2*] Improvement: improved internal threading ([#697][697]) -- [*Camera1, Camera2*] Improvement: improvements to stability and edge cases behavior ([#696][696]) -- [*Real time filters*] Change: filters do not need the experimental flag anymore ([#691][691]) +- [Camera2] New: support for RAW pictures with new APIs `setPictureFormat()` and `CameraOptions.getSupportedPictureFormats()`. Contains a **breaking change**: `PictureResult.getFormat()` is not an integer anymore but rather a `PictureFormat`. This API had no real purpose so this might not affect you ([#691][691]) +- [Camera2] New: support for constraining the frame processing size through `setFrameProcessingMaxWidth()` and `setFrameProcessingMaxHeight()`. This can improve processing performance ([#691][691]) +- [Camera2] New: support for choosing the frame processing format through `setFrameProcessingFormat()` and `CameraOptions.getSupportedFrameProcessingFormats()` ([#691][691]) +- [Camera2] Improvement: Frame processing FPS for Camera2 is now smooth and typically better than Camera1. This required some **breaking changes** (see below) ([#691][691]) +- [Camera1, Camera2] Improvement: improved internal threading ([#697][697]) +- [Camera1, Camera2] Improvement: improvements to stability and edge cases behavior ([#696][696]) +- [Real time filters] Change: filters do not need the experimental flag anymore ([#691][691]) The new frame processing approach will force you to update your code, because `Frame.getData()` is not a a byte[] anymore. The class of this object now depends on the engine being used. You can use @@ -36,47 +36,47 @@ https://github.com/natario1/CameraView/compare/v2.4.0...v2.5.0 ## v2.4.0 -- [*Camera2*] New: support for `previewFrameRate`. Controls preview FPS, snapshot FPS, processor FPS, thanks to [@vaibhavbhandula][vaibhavbhandula] ([#653][653]) -- [*Camera1*] New: support for `previewFrameRate` for Camera1 ([#661][661]) -- [*Camera2*] Fix: fix crashes when taking snapshots very early ([#651][651]) -- [*Preview*] Fix: Fixed preview being upside-down for 180 degrees flips ([#651][651]) +- [Camera2] New: support for `previewFrameRate`. Controls preview FPS, snapshot FPS, processor FPS, thanks to [@vaibhavbhandula][vaibhavbhandula] ([#653][653]) +- [Camera1] New: support for `previewFrameRate` for Camera1 ([#661][661]) +- [Camera2] Fix: fix crashes when taking snapshots very early ([#651][651]) +- [Preview] Fix: Fixed preview being upside-down for 180 degrees flips ([#651][651]) - Fix: other bug fixes ([#651][651]) https://github.com/natario1/CameraView/compare/v2.3.1...v2.4.0 ### v2.3.1 -- [*Video*] Improvement: better timing for `onVideoRecordingStart()` thanks to [@agrawalsuneet][agrawalsuneet] ([#632][632]) -- [*Video, Camera1*] Fix: fixed video errors when starting on specific devices ([#617][617]) -- [*Video*] Fix: fixed crash when closing the app during video snapshots ([#630][630]) -- [*Preview*] Fix: fixed crash when using `GL_SURFACE` ([#630][630]) +- [Video] Improvement: better timing for `onVideoRecordingStart()` thanks to [@agrawalsuneet][agrawalsuneet] ([#632][632]) +- [Video, Camera1] Fix: fixed video errors when starting on specific devices ([#617][617]) +- [Video] Fix: fixed crash when closing the app during video snapshots ([#630][630]) +- [Preview] Fix: fixed crash when using `GL_SURFACE` ([#630][630]) https://github.com/natario1/CameraView/compare/v2.3.0...v2.3.1 ## v2.3.0 -- [*Camera2, Metering*] New: `startAutoFocus` is much more powerful and does 3A metering (AF, AE, AWB) ([#574][574]) -- [*Camera2, Metering*] New: `setPictureMetering(boolean)` decides whether to do metering before `takePicture()`. Defaults to true to improve quality. ([#580][580]) -- [*Camera2, Metering*] New: `setPictureSnapshotMetering(boolean)` decides whether to do metering before `takePictureSnapshot()`. Defaults to false to improve latency. However, you can set this to true to greatly improve the snapshot quality, for example to support `Flash`. ([#580][580]) -- [*Camera2, Metering*] New: metering extended to many more cameras, which can now use `startAutoFocus` or the focus gesture ([#574][574]) -- [*Camera2, Metering*] Improvement: `onAutoFocusEnd` is now guaranteed to be called ([#574][574]) -- [*Camera2, Metering*] Improvement: taking picture does not invalidate the previous focus ([#574][574]) -- [*Camera2, Metering*] Improvement: better metering when zoomed in ([#574][574]) -- [*Real time filters*] **Breaking change**: `Filter` interface signatures now accept timestamps for animations ([#588][588]) -- [*Overlays*] New: you can now use `addView()` and `removeView()` to add or remove overlays at runtime (see docs) ([#588][588]) -- [*Video*] Improvement: better encoder selection ([#588][588]) +- [Camera2, Metering] New: `startAutoFocus` is much more powerful and does 3A metering (AF, AE, AWB) ([#574][574]) +- [Camera2, Metering] New: `setPictureMetering(boolean)` decides whether to do metering before `takePicture()`. Defaults to true to improve quality. ([#580][580]) +- [Camera2, Metering] New: `setPictureSnapshotMetering(boolean)` decides whether to do metering before `takePictureSnapshot()`. Defaults to false to improve latency. However, you can set this to true to greatly improve the snapshot quality, for example to support `Flash`. ([#580][580]) +- [Camera2, Metering] New: metering extended to many more cameras, which can now use `startAutoFocus` or the focus gesture ([#574][574]) +- [Camera2, Metering] Improvement: `onAutoFocusEnd` is now guaranteed to be called ([#574][574]) +- [Camera2, Metering] Improvement: taking picture does not invalidate the previous focus ([#574][574]) +- [Camera2, Metering] Improvement: better metering when zoomed in ([#574][574]) +- [Real time filters] **Breaking change**: `Filter` interface signatures now accept timestamps for animations ([#588][588]) +- [Overlays] New: you can now use `addView()` and `removeView()` to add or remove overlays at runtime (see docs) ([#588][588]) +- [Video] Improvement: better encoder selection ([#588][588]) - Fix: fixed various bugs and improved stability ([#588][588]) https://github.com/natario1/CameraView/compare/v2.2.0...v2.3.0 ## v2.2.0 -- [*Real time filters*] New: `SimpleFilter` class accepts a fragment shader in the constructor ([#552][552]) -- [*Real time filters*] New: `MultiFilter` to apply more than one filter at the same time ([#559][559]) -- [*Video*] Improvement: query device encoders before configuring them. Should fix issues on multiple devices ([#545][545]) -- [*Video*] Fix: `takeVideoSnapshot` not working unless you set a max duration ([#551][551]) -- [*Video*] Fix: `takeVideo` crashing on Camera2 LEGACY devices ([#551][551]) -- [*Frame Processing*] Fix: fixed dead Frames issues and improved error messages ([#572][572]) +- [Real time filters] New: `SimpleFilter` class accepts a fragment shader in the constructor ([#552][552]) +- [Real time filters] New: `MultiFilter` to apply more than one filter at the same time ([#559][559]) +- [Video] Improvement: query device encoders before configuring them. Should fix issues on multiple devices ([#545][545]) +- [Video] Fix: `takeVideoSnapshot` not working unless you set a max duration ([#551][551]) +- [Video] Fix: `takeVideo` crashing on Camera2 LEGACY devices ([#551][551]) +- [Frame Processing] Fix: fixed dead Frames issues and improved error messages ([#572][572]) - Fix: fixed `CameraView` appearance in the layout editor ([#564][564]) https://github.com/natario1/CameraView/compare/v2.1.0...v2.2.0 diff --git a/docs/_posts/2018-12-20-runtime-permissions.md b/docs/_posts/2018-12-20-runtime-permissions.md index 1a44eb2e..0b7ed22a 100644 --- a/docs/_posts/2018-12-20-runtime-permissions.md +++ b/docs/_posts/2018-12-20-runtime-permissions.md @@ -39,11 +39,14 @@ device has cameras, and then start the camera view. ### Handling -On Marshmallow+, the user must explicitly approve our permissions. You can +On Marshmallow+, the user must explicitly approve our permissions. You can either: - handle permissions yourself and then call `open()` or `setLifecycleOwner()` once they are acquired -- ignore this: `CameraView` will present a permission request to the user based on +- let `CameraView` request permissions: we will present a permission request to the user based on whether they are needed or not with the current configuration. -Note however, that this is done at the activity level, so the permission request callback -`onRequestPermissionResults()` will be invoked on the parent activity, not the fragment. \ No newline at end of file +The automatic request is currently done at the activity level, so the permission request callback +`onRequestPermissionResults()` will be invoked on the parent activity, not the fragment. + +The automatic request can be disabled by setting `app:cameraRequestPermissions="false"` in your +XML declaration. \ No newline at end of file diff --git a/docs/css/main.css b/docs/css/main.css index fbb1438f..761cdd22 100644 --- a/docs/css/main.css +++ b/docs/css/main.css @@ -1,21 +1,29 @@ +@import url('https://fonts.googleapis.com/css?family=Calistoga|Roboto+Mono|Source+Sans+Pro:400,700&display=swap'); + body { font-weight: 400; + font-family: 'Source Sans Pro', sans-serif; +} + +h1, h2, h3, h4, h5, h6, th { + font-family: 'Calistoga', sans-serif; +} + +small { + font-weight: 400; + font-family: 'Source Sans Pro', sans-serif; } pre, code, pre code { border: none; border-radius: 0; - background-color: #f9f9f9; - font-size: 1em; + background-color: #fafafa; + font-size: 0.8em; } .highlight { - background-color: #f9f9f9; -} - -/* This changes inline code and hopefully nothing else */ -.highlighter-rouge { - color: #336699 + background-color: #fafafa; + border-radius: 12px; } pre { @@ -24,6 +32,12 @@ pre { code { color: inherit; + font-family: 'Roboto Mono', monospace; + color: #dd2200; +} + +a { + color: #0e95e3; } #header { @@ -35,6 +49,27 @@ code { text-decoration: none; } +#content { + /* bigger font */ + font-size: 1.1em; +} + +#content p { + /* spacing for all paragraphs */ + margin-top: 16px; + margin-bottom: 16px; +} + +#content ul li { + /* spacing for lists */ + margin-top: 8px; + margin-bottom: 8px; +} + +#content h5 { + font-size: 1.1em; +} + #footer { margin: 20px 0; font-size: 0.85em; @@ -50,14 +85,27 @@ code { margin-top: 0; } +#content .page-subtitle { + font-size: 0.45em; +} #navigation { - font-size: 0.9em; + font-size: 1.0em; } #navigation li a { - padding-left: 10px; - padding-right: 10px; + padding-left: 16px; + padding-right: 16px; + border-radius: 32px; +} + +#navigation li a:hover { + background: #fafafa; +} + +#navigation li.active a { + background: #f76c16; + color: #FFFFFF; } #navigation .nav-header { @@ -68,10 +116,11 @@ code { } .nav-header { - font-size: 1em; + font-size: 1.1em; cursor: default; - text-transform: uppercase; + /* text-transform: uppercase; */ font-weight: bold; + font-family: 'Calistoga', sans-serif; } body.rtl { @@ -114,4 +163,5 @@ td { th { padding: 8px 12px; border: 1px solid #e5e5e5; + font-weight: 400; } diff --git a/docs/css/syntax.css b/docs/css/syntax.css index 4877e415..d2080cad 100644 --- a/docs/css/syntax.css +++ b/docs/css/syntax.css @@ -6,7 +6,7 @@ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .c1 { color: #888888 } /* Comment.Single */ -.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ +.highlight .cs { color: #cc0000; font-weight: bold; /* background-color: #fff0f0 */ } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ diff --git a/docs/index.md b/docs/index.md index 097a59d0..2e57eb31 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,6 +1,6 @@ --- layout: default -title: "CameraView v2" +title: "CameraView" --- # CameraView