├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Makefile
├── README.md
├── UNLICENSE
├── app
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── de
│ │ └── markusfisch
│ │ └── android
│ │ └── cameraviewdemo
│ │ └── activity
│ │ └── MainActivity.java
│ └── res
│ └── values
│ └── strings.xml
├── build.gradle
├── cameraview
├── build.gradle
└── src
│ └── main
│ └── java
│ └── de
│ └── markusfisch
│ └── android
│ └── cameraview
│ └── widget
│ └── CameraView.java
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | .gradle
3 | .idea
4 | build
5 | local.properties
6 | gradle.properties
7 | infer-out
8 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | ## 1.10.0
4 | * Add setScaleType to control camera preview layout
5 |
6 | ## 1.9.2
7 | * Remove appcompat dependency
8 |
9 | ## 1.9.1
10 | * Don't reset touch listener in focusTo()
11 |
12 | ## 1.9.0
13 | * Add focusTo() to manually focus to some spot
14 |
15 | ## 1.8.4
16 | * Catch possible RuntimeException on autoFocus()
17 |
18 | ## 1.8.3
19 | * Terminate HandlerThread after closing camera
20 |
21 | ## 1.8.2
22 | * Make CameraView.PreviewCallback.onPreviewFrame() run in a background thread
23 | * Forward camera errors to OnCameraListener.onCameraError()
24 |
25 | ## 1.8.1
26 | * Reactivate JitPack support
27 |
28 | ## 1.8.0
29 | * Adds setTapToFocus() to enable tap to focus
30 |
31 | ## 1.7.2
32 | * Expose findBestPreviewSize() to ease setting a custom preview size
33 |
34 | ## 1.7.1
35 | * Allow setting a custom preview size in onConfigureParameters()
36 |
37 | ## 1.7.0
38 | * Improve reliability of opening the camera
39 | * Does only restart the camera for 180deg changes in orientation listener
40 |
41 | ## 1.6.0
42 | * Add setUseOrientationListener() to fix landscape to landscape rotations
43 |
44 | ## 1.5.0
45 | * Fix relative camera orientation for front facing cameras
46 | * Rename OnCameraListener.onCameraStarted() to onCameraReady()
47 |
48 | ## 1.4.0
49 | * Adds OnCameraListener.onPreviewStarted() callback
50 |
51 | ## 1.3.3
52 | * Fixed Gradle configuration for JitPack again
53 |
54 | ## 1.3.2
55 | * Fixed Gradle configuration for JitPack
56 |
57 | ## 1.3.1
58 | * Fixed closing the camera immediately after openAsync()
59 |
60 | ## 1.3.0
61 | * Helper functions to easily set a focus area (required for tap to focus)
62 |
63 | ## 1.2.1
64 | * Fixes two formal issues static analyzers will complain about
65 |
66 | ## 1.2.0
67 | * OnCameraListener.onCameraError() gets called when Camera.open() fails too
68 |
69 | ## 1.1.0
70 | * CameraView.setAutoFocus() must be called manually now
71 | * Handle camera errors in OnCameraListener.onCameraError()
72 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribution Guidelines
2 |
3 | Please try to keep things in good shape and comply to what's there.
4 |
5 | This project follows Android [best practices][android_best_practices]
6 | so please have a look if you've never heard of them.
7 |
8 | The code is formatted according to Android Studio's standard, with the
9 | exception of indent being tabs instead of spaces.
10 |
11 | Use the feature branch workflow to add new features and make sure
12 | to squash when merging into master:
13 |
14 | $ git merge cool_feature --squash
15 |
16 | Then write a [good commit message][commit_messages] to keep the history
17 | meaningful and useful. One feature, one commit.
18 |
19 | [android_best_practices]: https://developer.android.com/distribute/best-practices/develop/
20 | [commit_messages]: https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines
21 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | PACKAGE = de.markusfisch.android.cameraviewdemo
2 |
3 | all: debug install start
4 |
5 | debug:
6 | ./gradlew assembleDebug
7 |
8 | lint:
9 | ./gradlew lintDebug
10 |
11 | infer: clean
12 | infer -- ./gradlew assembleDebug
13 |
14 | release: lint
15 | ./gradlew assembleRelease
16 |
17 | aar: clean
18 | ./gradlew :cameraview:assembleRelease
19 |
20 | install:
21 | adb $(TARGET) install -r app/build/outputs/apk/debug/app-debug.apk
22 |
23 | start:
24 | adb $(TARGET) shell 'am start -n $(PACKAGE)/.activity.MainActivity'
25 |
26 | uninstall:
27 | adb $(TARGET) uninstall $(PACKAGE)
28 |
29 | clean:
30 | ./gradlew clean
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CameraView
2 |
3 | Camera view for Android. Supports orientation changes, fits preview image
4 | into available view space and works with Gingerbread (minSDK 9) or better
5 | (since it still uses the deprecated Camera API). All in just ~500 lines of
6 | code.
7 |
8 | ## Why the deprecated Camera API?
9 |
10 | This library is deliberately still on API level 9 (Android 2.3).
11 |
12 | If you're not interested in supporting old versions of Android and/or
13 | don't want to use the deprecated Camera API on newer devices, have a look at
14 | the [CameraX support library](https://developer.android.com/training/camerax)
15 | (available from API level 21).
16 |
17 | There, we finally find
18 | [PreviewView](https://developer.android.com/reference/androidx/camera/view/PreviewView)
19 | as part of the SDK. You can read
20 | [here](https://developer.android.com/training/camerax/preview)
21 | how to implement it.
22 |
23 | ## How to include
24 |
25 | ### Gradle
26 |
27 | Add the JitPack repository in your root build.gradle at the end of
28 | repositories:
29 |
30 | ```groovy
31 | allprojects {
32 | repositories {
33 | …
34 | maven { url 'https://jitpack.io' }
35 | }
36 | }
37 | ```
38 |
39 | Then add the dependency in your app/build.gradle:
40 |
41 | ```groovy
42 | dependencies {
43 | implementation 'com.github.markusfisch:CameraView:1.10.0'
44 | }
45 | ```
46 |
47 | ### Manually
48 |
49 | Alternatively you may just download the latest `aar` from
50 | [Releases](https://github.com/markusfisch/CameraView/releases) and put it
51 | into `app/libs` in your app.
52 |
53 | Then make sure your `app/build.gradle` contains the following line in the
54 | `dependencies` block:
55 |
56 | ```groovy
57 | dependencies {
58 | implementation fileTree(dir: 'libs', include: '*')
59 | …
60 | }
61 | ```
62 |
63 | ## How to use
64 |
65 | Add it to a layout:
66 |
67 | ```xml
68 |
73 | ```
74 |
75 | Or create it in Java:
76 |
77 | ```java
78 | import de.markusfisch.android.cameraview.widget.CameraView;
79 |
80 | CameraView cameraView = new CameraView(context);
81 | ```
82 |
83 | If your app supports *orientation changes*, please also enable the built-in
84 | orientation listener:
85 |
86 | ```java
87 | cameraView.setUseOrientationListener(true);
88 | ```
89 |
90 | This will take care of landscape to reverse landscape rotations (and vice
91 | versa). Without this, Android will re-use the Activity without calling a
92 | life cycle method what will result in an upside down camera preview.
93 |
94 | Run `CameraView.openAsync()`/`.close()` in `onResume()`/`onPause()` of
95 | your activity or fragment:
96 |
97 | ```java
98 | @Override
99 | public void onResume() {
100 | super.onResume();
101 | cameraView.openAsync(CameraView.findCameraId(
102 | Camera.CameraInfo.CAMERA_FACING_BACK));
103 | }
104 |
105 | @Override
106 | public void onPause() {
107 | super.onPause();
108 | cameraView.close();
109 | }
110 | ```
111 |
112 | To set custom camera parameters or a preview listener to get the camera
113 | frame, set an OnCameraListener:
114 |
115 | ```java
116 | cameraView.setOnCameraListener(new OnCameraListener {
117 | @Override
118 | public void onConfigureParameters(Camera.Parameters parameters) {
119 | // set additional camera parameters here
120 | }
121 |
122 | @Override
123 | public void onCameraError() {
124 | // handle camera errors
125 | }
126 |
127 | @Override
128 | public void onCameraReady(Camera camera) {
129 | // set a preview listener
130 | }
131 |
132 | @Override
133 | public void onPreviewStarted(Camera camera) {
134 | // start processing camera data
135 | }
136 |
137 | @Override
138 | public void onCameraStopping(Camera camera) {
139 | // clean up
140 | }
141 | });
142 | ```
143 |
144 | ## Preview resolution
145 |
146 | By default CameraView picks the camera preview resolution that is closest
147 | to the size of the view on screen. If you want a lower or higher resolution,
148 | you may use `CameraView.findBestPreviewSize()` (or a customized copy of it)
149 | in `OnCameraListener.onConfigureParameters()` to pick another size.
150 |
151 | For example, if you want to pick the highest possible resolution, you can
152 | do this:
153 |
154 | ```java
155 | cameraView.setOnCameraListener(new OnCameraListener {
156 | @Override
157 | public void onConfigureParameters(Camera.Parameters parameters) {
158 | Camera.Size size = findBestPreviewSize(
159 | parameters.getSupportedPreviewSizes(),
160 | cameraView.getFrameWidth() * 1000,
161 | cameraView.getFrameHeight() * 1000);
162 | parameters.setPreviewSize(size.width, size.height);
163 | …
164 | }
165 | …
166 | ```
167 |
168 | `CameraView.findBestPreviewSize()` returns the preview resolution that has
169 | the smallest absolute distance to the given dimensions *and* is as close to
170 | the aspect ratio of those dimensions as possible.
171 |
172 | ## Preview layout
173 |
174 | On some devices, the camera frame has a different aspect ratio than the
175 | screen. The camera preview can either be laid so that it completely covers
176 | the available `View` area (which is `SCALE_TYPE_CENTER_CROP`, the default),
177 | or so that it lies completely within it (`SCALE_TYPE_CENTER_INSIDE`).
178 |
179 | Use `CameraView.setScaleType()` with the appropriate constant:
180 |
181 | ```java
182 | cameraView.setScaleType(CameraView.SCALE_TYPE_CENTER_INSIDE);
183 | ```
184 |
185 | ## Auto Focus
186 |
187 | To enable Auto Focus, you should run `CameraView.setAutoFocus()` in
188 | `OnCameraListener.onConfigureParameters()`:
189 |
190 | ```java
191 | cameraView.setOnCameraListener(new OnCameraListener {
192 | @Override
193 | public void onConfigureParameters(Camera.Parameters parameters) {
194 | CameraView.setAutoFocus(parameters);
195 | …
196 | }
197 | …
198 | ```
199 |
200 | `CameraView.setAutoFocus()` picks the best available Auto Focus mode for
201 | making pictures. If you want something else, just have a look at this
202 | method and re-implement it in the client to fit your needs.
203 |
204 | Note that Auto Focus is not available on all devices. If your app depends
205 | on Auto Focus, you should put a `` tag in your
206 | `AndroidManifest.xml` to make Google Play restrict your app to devices
207 | that sport this feature:
208 |
209 | ```xml
210 |
211 | ```
212 |
213 | ## Tap to focus
214 |
215 | To make the CameraView focus where a user taps, simply call `setTapToFocus()`
216 | on your `cameraView` instance:
217 |
218 | ```java
219 | cameraView.setTapToFocus();
220 | ```
221 |
222 | This adds a `View.OnTouchListener` to the `CameraView` to process the tap.
223 |
224 | If you want to use a custom `View.OnTouchListener`, you can call `focusTo()`
225 | manually in your touch listener instead of using `setTapToFocus()`:
226 |
227 | ```java
228 | if (event.getActionMasked() == MotionEvent.ACTION_UP) {
229 | boolean success = focusTo(cameraView, event.getX(), event.getY());
230 | …
231 | }
232 | ```
233 |
234 | If `focusTo()` returns `false`, you should stop calling it because that
235 | means there was a `RuntimeException` that will be thrown (and catched) in
236 | the future too.
237 |
238 | ## Scene modes
239 |
240 | You may use a predefined scene mode to use optimized camera parameters for
241 | a specific purpose. Consequently, setting a scene mode may override previously
242 | set camera parameters, of course.
243 |
244 | For example, to use `SCENE_MODE_BARCODE` (if it's available) do:
245 |
246 | ```java
247 | cameraView.setOnCameraListener(new OnCameraListener {
248 | @Override
249 | public void onConfigureParameters(Camera.Parameters parameters) {
250 | List modes = parameters.getSupportedSceneModes();
251 | if (modes != null) {
252 | for (String mode : modes) {
253 | if (Camera.Parameters.SCENE_MODE_BARCODE.equals(mode)) {
254 | parameters.setSceneMode(mode);
255 | break;
256 | }
257 | }
258 | }
259 | …
260 | }
261 | …
262 | ```
263 |
264 | Please note, not all devices support scene modes.
265 |
266 | ## Demo
267 |
268 | You can run the enclosed demo app to see if this widget is what you want.
269 | Either import it into Android Studio or, if you're not on that thing from
270 | Redmond, just type `make` to build, install and run.
271 |
272 | Tap on the screen to switch between the front and back camera.
273 |
274 | ## License
275 |
276 | This widget is so basic, it should be Public Domain. And it is.
277 |
--------------------------------------------------------------------------------
/UNLICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | namespace 'de.markusfisch.android.cameraviewdemo'
5 | compileSdkVersion sdk_version
6 |
7 | defaultConfig {
8 | minSdkVersion 9
9 | targetSdkVersion sdk_version
10 |
11 | versionCode 1
12 | versionName '0.0.0'
13 | }
14 | }
15 |
16 | dependencies {
17 | implementation project(':cameraview')
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
8 |
9 |
10 |
11 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/java/de/markusfisch/android/cameraviewdemo/activity/MainActivity.java:
--------------------------------------------------------------------------------
1 | package de.markusfisch.android.cameraviewdemo.activity;
2 |
3 | import android.app.Activity;
4 | import android.content.pm.PackageManager;
5 | import android.hardware.Camera;
6 | import android.os.Build;
7 | import android.os.Bundle;
8 | import android.view.Window;
9 | import android.view.WindowManager;
10 | import android.widget.Toast;
11 |
12 | import de.markusfisch.android.cameraview.widget.CameraView;
13 | import de.markusfisch.android.cameraviewdemo.R;
14 |
15 | public class MainActivity extends Activity {
16 | private static final int REQUEST_CAMERA = 1;
17 |
18 | private static boolean frontFacing = false;
19 |
20 | private CameraView cameraView;
21 |
22 | @Override
23 | public void onRequestPermissionsResult(
24 | int requestCode,
25 | String[] permissions,
26 | int[] grantResults) {
27 | if (requestCode == REQUEST_CAMERA &&
28 | grantResults.length > 0 &&
29 | grantResults[0] != PackageManager.PERMISSION_GRANTED) {
30 | Toast.makeText(
31 | this,
32 | R.string.error_camera,
33 | Toast.LENGTH_SHORT).show();
34 | finish();
35 | }
36 | }
37 |
38 | @Override
39 | protected void onCreate(Bundle state) {
40 | super.onCreate(state);
41 |
42 | requestWindowFeature(Window.FEATURE_NO_TITLE);
43 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
44 |
45 | checkPermissions();
46 |
47 | cameraView = new CameraView(this);
48 | cameraView.setUseOrientationListener(true);
49 | cameraView.setOnClickListener(v -> invertCamera());
50 |
51 | setContentView(cameraView);
52 | }
53 |
54 | @Override
55 | public void onResume() {
56 | super.onResume();
57 | openCameraView();
58 | }
59 |
60 | @Override
61 | public void onPause() {
62 | super.onPause();
63 | closeCameraView();
64 | }
65 |
66 | private void checkPermissions() {
67 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
68 | String permission = android.Manifest.permission.CAMERA;
69 | if (checkSelfPermission(permission) !=
70 | PackageManager.PERMISSION_GRANTED) {
71 | requestPermissions(new String[]{permission}, REQUEST_CAMERA);
72 | }
73 | }
74 | }
75 |
76 | private void openCameraView() {
77 | cameraView.openAsync(CameraView.findCameraId(getFacing()));
78 | }
79 |
80 | private void closeCameraView() {
81 | cameraView.close();
82 | }
83 |
84 | private void invertCamera() {
85 | frontFacing ^= true;
86 | closeCameraView();
87 | openCameraView();
88 | }
89 |
90 | private int getFacing() {
91 | return frontFacing ?
92 | Camera.CameraInfo.CAMERA_FACING_FRONT :
93 | Camera.CameraInfo.CAMERA_FACING_BACK;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CameraView
3 | Cannot open camera
4 |
5 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | tools_version = '7.2.0'
4 | sdk_version = 34
5 | }
6 |
7 | repositories {
8 | google()
9 | mavenCentral()
10 | }
11 |
12 | dependencies {
13 | classpath "com.android.tools.build:gradle:$tools_version"
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | mavenCentral()
21 | }
22 |
23 | gradle.projectsEvaluated {
24 | tasks.withType(JavaCompile) {
25 | options.compilerArgs << "-Xlint:unchecked"
26 | }
27 | }
28 | }
29 |
30 | task clean(type: Delete) {
31 | delete rootProject.buildDir
32 | }
33 |
--------------------------------------------------------------------------------
/cameraview/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | }
6 |
7 | dependencies {
8 | classpath "com.android.tools.build:gradle:$tools_version"
9 | }
10 | }
11 |
12 | apply plugin: 'com.android.library'
13 | apply plugin: 'maven-publish'
14 |
15 | android {
16 | namespace 'de.markusfisch.android.cameraview'
17 | compileSdkVersion sdk_version
18 |
19 | defaultConfig {
20 | minSdkVersion 9
21 | targetSdkVersion sdk_version
22 |
23 | versionCode 22
24 | versionName '1.10.0'
25 | }
26 | }
27 |
28 | afterEvaluate {
29 | publishing {
30 | publications {
31 | release(MavenPublication) {
32 | from components.release
33 | groupId = 'com.github.markusfisch'
34 | artifactId = 'final'
35 | version = '1.10.0'
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/cameraview/src/main/java/de/markusfisch/android/cameraview/widget/CameraView.java:
--------------------------------------------------------------------------------
1 | package de.markusfisch.android.cameraview.widget;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.annotation.TargetApi;
5 | import android.content.Context;
6 | import android.graphics.Rect;
7 | import android.hardware.Camera;
8 | import android.hardware.SensorManager;
9 | import android.os.Build;
10 | import android.os.Handler;
11 | import android.os.HandlerThread;
12 | import android.util.AttributeSet;
13 | import android.view.Display;
14 | import android.view.MotionEvent;
15 | import android.view.OrientationEventListener;
16 | import android.view.Surface;
17 | import android.view.SurfaceHolder;
18 | import android.view.SurfaceView;
19 | import android.view.View;
20 | import android.view.WindowManager;
21 | import android.widget.FrameLayout;
22 |
23 | import java.io.IOException;
24 | import java.util.ArrayList;
25 | import java.util.List;
26 |
27 | public class CameraView extends FrameLayout {
28 | public interface OnCameraListener {
29 | void onConfigureParameters(Camera.Parameters parameters);
30 |
31 | void onCameraError();
32 |
33 | void onCameraReady(Camera camera);
34 |
35 | void onPreviewStarted(Camera camera);
36 |
37 | void onCameraStopping(Camera camera);
38 | }
39 |
40 | public static final int SCALE_TYPE_CENTER_CROP = 0;
41 | public static final int SCALE_TYPE_CENTER_INSIDE = 1;
42 |
43 | public final Rect previewRect = new Rect();
44 |
45 | private final Runnable focusRunnable = new Runnable() {
46 | @Override
47 | public void run() {
48 | setFocusArea(null);
49 | }
50 | };
51 |
52 | private boolean isOpen = false;
53 | private boolean useOrientationListener = false;
54 | private OnCameraListener cameraListener;
55 | private HandlerThread cameraCallbackThread;
56 | private Camera cam;
57 | private OrientationEventListener orientationListener;
58 | private int scaleType = SCALE_TYPE_CENTER_CROP;
59 | private int tries = 0;
60 | private int viewWidth;
61 | private int viewHeight;
62 | private int frameWidth;
63 | private int frameHeight;
64 | private int frameOrientation;
65 |
66 | public static int findCameraId(int facing) {
67 | for (int i = 0, l = Camera.getNumberOfCameras(); i < l; ++i) {
68 | Camera.CameraInfo info = new Camera.CameraInfo();
69 | Camera.getCameraInfo(i, info);
70 | if (info.facing == facing) {
71 | return i;
72 | }
73 | }
74 | return -1;
75 | }
76 |
77 | public static int getRelativeCameraOrientation(
78 | Context context,
79 | int cameraId) {
80 | Camera.CameraInfo info = new Camera.CameraInfo();
81 | Camera.getCameraInfo(cameraId, info);
82 | int orientation = info.orientation;
83 | if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
84 | orientation -= 180;
85 | }
86 | return (orientation - getDeviceRotation(context) + 360) % 360;
87 | }
88 |
89 | public static int getDeviceRotation(Context context) {
90 | switch (((WindowManager) context
91 | .getSystemService(Context.WINDOW_SERVICE))
92 | .getDefaultDisplay()
93 | .getRotation()) {
94 | case Surface.ROTATION_90:
95 | return 90;
96 | case Surface.ROTATION_180:
97 | return 180;
98 | case Surface.ROTATION_270:
99 | return 270;
100 | case Surface.ROTATION_0:
101 | default:
102 | return 0;
103 | }
104 | }
105 |
106 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
107 | public static boolean setAutoFocus(Camera.Parameters parameters) {
108 | // best for taking pictures, API >= ICE_CREAM_SANDWICH
109 | String continuousPicture =
110 | Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE;
111 | // less aggressive than CONTINUOUS_PICTURE, API >= GINGERBREAD
112 | String continuousVideo =
113 | Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO;
114 | // last resort
115 | String autoFocus = Camera.Parameters.FOCUS_MODE_AUTO;
116 |
117 | // prefer feature detection instead of checking BUILD.VERSION
118 | List focusModes = parameters.getSupportedFocusModes();
119 |
120 | if (focusModes.contains(continuousPicture)) {
121 | parameters.setFocusMode(continuousPicture);
122 | } else if (focusModes.contains(continuousVideo)) {
123 | parameters.setFocusMode(continuousVideo);
124 | } else if (focusModes.contains(autoFocus)) {
125 | parameters.setFocusMode(autoFocus);
126 | } else {
127 | return false;
128 | }
129 |
130 | return true;
131 | }
132 |
133 | // overriding `View.performClick()` wouldn't make any sense here
134 | @SuppressLint("ClickableViewAccessibility")
135 | public void setTapToFocus() {
136 | setOnTouchListener(new View.OnTouchListener() {
137 | @Override
138 | public boolean onTouch(View v, MotionEvent event) {
139 | if (event.getActionMasked() == MotionEvent.ACTION_UP &&
140 | !focusTo(v, event.getX(), event.getY())) {
141 | v.setOnTouchListener(null);
142 | return false;
143 | }
144 | v.performClick();
145 | return true;
146 | }
147 | });
148 | }
149 |
150 | public boolean focusTo(final View v, float x, float y) {
151 | if (cam == null) {
152 | return false;
153 | }
154 | // catch possible RuntimeException's for autoFocus()
155 | // as there a devices with broken camera drivers
156 | try {
157 | cam.cancelAutoFocus();
158 | if (!setFocusArea(calculateFocusRect(x, y, 100))) {
159 | return false;
160 | }
161 | cam.autoFocus(new Camera.AutoFocusCallback() {
162 | @Override
163 | public void onAutoFocus(boolean success, Camera camera) {
164 | v.removeCallbacks(focusRunnable);
165 | v.postDelayed(focusRunnable, 3000);
166 | }
167 | });
168 | } catch (RuntimeException e) {
169 | return false;
170 | }
171 | return true;
172 | }
173 |
174 | public static Camera.Size findBestPreviewSize(
175 | List sizes,
176 | int width,
177 | int height) {
178 | final double ASPECT_TOLERANCE = 0.1;
179 | double targetRatio = (double) width / height;
180 | double minDiff = Double.MAX_VALUE;
181 | double minDiffAspect = Double.MAX_VALUE;
182 | Camera.Size bestSize = null;
183 | Camera.Size bestSizeAspect = null;
184 |
185 | for (Camera.Size size : sizes) {
186 | double diff = (double) Math.abs(size.height - height) +
187 | Math.abs(size.width - width);
188 |
189 | if (diff < minDiff) {
190 | bestSize = size;
191 | minDiff = diff;
192 | }
193 |
194 | double ratio = (double) size.width / size.height;
195 |
196 | if (Math.abs(ratio - targetRatio) < ASPECT_TOLERANCE &&
197 | diff < minDiffAspect) {
198 | bestSizeAspect = size;
199 | minDiffAspect = diff;
200 | }
201 | }
202 |
203 | return bestSizeAspect != null ? bestSizeAspect : bestSize;
204 | }
205 |
206 | public CameraView(Context context) {
207 | super(context);
208 | }
209 |
210 | public CameraView(Context context, AttributeSet attrs) {
211 | super(context, attrs);
212 | }
213 |
214 | public CameraView(
215 | Context context,
216 | AttributeSet attrs,
217 | int defStyleAttr) {
218 | super(context, attrs, defStyleAttr);
219 | }
220 |
221 | public void setUseOrientationListener(boolean use) {
222 | useOrientationListener = use;
223 | }
224 |
225 | public void setScaleType(int scaleType) {
226 | this.scaleType = scaleType;
227 | }
228 |
229 | public void openAsync(final int cameraId) {
230 | if (isOpen || cameraCallbackThread != null) {
231 | return;
232 | }
233 | isOpen = true;
234 | // use a HandlerThread so future preview callbacks are invoked
235 | // from this background thread; an AsyncTask is terminated after
236 | // runInBackground() ends
237 | cameraCallbackThread = new HandlerThread(
238 | "CameraCallbackHandlerThread");
239 | cameraCallbackThread.start();
240 | Handler callbackThreadHandler = new Handler(
241 | cameraCallbackThread.getLooper());
242 | callbackThreadHandler.post(new Runnable() {
243 | @Override
244 | public void run() {
245 | // abort if there's already an open camera
246 | if (cam != null) {
247 | return;
248 | }
249 | // Camera.open() may take a while so it shouldn't be
250 | // invoked on the main thread according to the docs
251 | final Camera camera = openCameraAndCatch(cameraId);
252 | CameraView.this.post(new Runnable() {
253 | @Override
254 | public void run() {
255 | initCamera(camera, cameraId);
256 | }
257 | });
258 | }
259 | });
260 | }
261 |
262 | public void close() {
263 | isOpen = false;
264 | if (orientationListener != null) {
265 | orientationListener.disable();
266 | orientationListener = null;
267 | }
268 | if (cam != null) {
269 | if (cameraListener != null) {
270 | cameraListener.onCameraStopping(cam);
271 | }
272 | cam.stopPreview();
273 | cam.setPreviewCallback(null);
274 | cam.release();
275 | cam = null;
276 | }
277 | if (cameraCallbackThread != null) {
278 | // terminate cameraCallbackThread, discard all pending messages
279 | cameraCallbackThread.quit();
280 | try {
281 | cameraCallbackThread.join();
282 | } catch (InterruptedException ignore) {
283 | }
284 | cameraCallbackThread = null;
285 | }
286 | removeAllViews();
287 | }
288 |
289 | public void setOnCameraListener(OnCameraListener listener) {
290 | cameraListener = listener;
291 | }
292 |
293 | public Camera getCamera() {
294 | return cam;
295 | }
296 |
297 | public int getFrameWidth() {
298 | return frameWidth;
299 | }
300 |
301 | public int getFrameHeight() {
302 | return frameHeight;
303 | }
304 |
305 | public int getFrameOrientation() {
306 | return frameOrientation;
307 | }
308 |
309 | public Rect calculateFocusRect(float x, float y, int radius) {
310 | int cx = Math.round(2000f / viewWidth * x - 1000f);
311 | int cy = Math.round(2000f / viewHeight * y - 1000f);
312 | return new Rect(
313 | Math.max(-1000, cx - radius),
314 | Math.max(-1000, cy - radius),
315 | Math.min(1000, cx + radius),
316 | Math.min(1000, cy + radius));
317 | }
318 |
319 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
320 | public boolean setFocusArea(Rect area) {
321 | if (cam == null || Build.VERSION.SDK_INT <
322 | Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
323 | return false;
324 | }
325 | try {
326 | Camera.Parameters parameters = cam.getParameters();
327 | if (parameters.getMaxNumFocusAreas() > 0) {
328 | if (area != null) {
329 | List focusAreas =
330 | new ArrayList();
331 | focusAreas.add(new Camera.Area(area, 1000));
332 | parameters.setFocusAreas(focusAreas);
333 | parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
334 | } else {
335 | parameters.setFocusAreas(null);
336 | CameraView.setAutoFocus(parameters);
337 | }
338 | }
339 | cam.setParameters(parameters);
340 | return true;
341 | } catch (RuntimeException e) {
342 | return false;
343 | }
344 | }
345 |
346 | @Override
347 | protected void onLayout(
348 | boolean changed,
349 | int left,
350 | int top,
351 | int right,
352 | int bottom) {
353 | if (!changed) {
354 | return;
355 | }
356 | viewWidth = right - left;
357 | viewHeight = bottom - top;
358 | if (cam != null && getChildCount() == 0) {
359 | Context context = getContext();
360 | if (context == null) {
361 | return;
362 | }
363 | addPreview(context);
364 | }
365 | }
366 |
367 | private static Camera openCameraAndCatch(int cameraId) {
368 | try {
369 | return Camera.open(cameraId);
370 | } catch (RuntimeException e) {
371 | return null;
372 | }
373 | }
374 |
375 | private void initCamera(Camera camera, int cameraId) {
376 | if (!isOpen) {
377 | // close() was called while Camera.open() was
378 | // running on another thread
379 | if (camera != null) {
380 | camera.release();
381 | }
382 | return;
383 | }
384 | if (camera == null) {
385 | if (cameraListener != null &&
386 | // only invoke onCameraError() if there
387 | // isn't an open camera yet
388 | cam == null) {
389 | if (tries < 3) {
390 | isOpen = false;
391 | openAsync(cameraId);
392 | ++tries;
393 | } else {
394 | cameraListener.onCameraError();
395 | }
396 | }
397 | return;
398 | }
399 | tries = 0;
400 | cam = camera;
401 | camera.setErrorCallback(new Camera.ErrorCallback() {
402 | public void onError(int error, Camera camera) {
403 | if (cameraListener != null) {
404 | cameraListener.onCameraError();
405 | }
406 | }
407 | });
408 | Context context = getContext();
409 | if (context == null) {
410 | close();
411 | return;
412 | }
413 | if (useOrientationListener) {
414 | enableOrientationListener(context, cameraId);
415 | }
416 | frameOrientation = getRelativeCameraOrientation(context, cameraId);
417 | if (viewWidth > 0) {
418 | addPreview(context);
419 | }
420 | }
421 |
422 | private void enableOrientationListener(Context context,
423 | final int cameraId) {
424 | final Display defaultDisplay = ((WindowManager) context
425 | .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
426 | final int defaultOrientation = defaultDisplay.getRotation();
427 | orientationListener = new OrientationEventListener(context,
428 | SensorManager.SENSOR_DELAY_NORMAL) {
429 | @Override
430 | public void onOrientationChanged(int orientation) {
431 | if (Math.abs(defaultOrientation -
432 | defaultDisplay.getRotation()) == 2) {
433 | close();
434 | openAsync(cameraId);
435 | }
436 | }
437 | };
438 | orientationListener.enable();
439 | }
440 |
441 | private void addPreview(Context context) {
442 | boolean transpose;
443 | try {
444 | transpose = setCameraParameters();
445 | } catch (RuntimeException e) {
446 | if (cameraListener != null) {
447 | cameraListener.onCameraError();
448 | }
449 | return;
450 | }
451 | int childWidth;
452 | int childHeight;
453 | if (transpose) {
454 | childWidth = frameHeight;
455 | childHeight = frameWidth;
456 | } else {
457 | childWidth = frameWidth;
458 | childHeight = frameHeight;
459 | }
460 | addSurfaceView(context, childWidth, childHeight);
461 | if (cameraListener != null) {
462 | cameraListener.onCameraReady(cam);
463 | }
464 | }
465 |
466 | private boolean setCameraParameters() throws RuntimeException {
467 | boolean transpose = frameOrientation == 90 || frameOrientation == 270;
468 | Camera.Parameters parameters = cam.getParameters();
469 | parameters.setRotation(frameOrientation);
470 | setPreviewSize(parameters, transpose);
471 | if (cameraListener != null) {
472 | cameraListener.onConfigureParameters(parameters);
473 | }
474 | Camera.Size size = parameters.getPreviewSize();
475 | if (size != null) {
476 | frameWidth = size.width;
477 | frameHeight = size.height;
478 | }
479 | cam.setParameters(parameters);
480 | cam.setDisplayOrientation(frameOrientation);
481 | return transpose;
482 | }
483 |
484 | private void setPreviewSize(
485 | Camera.Parameters parameters,
486 | boolean transpose) {
487 | if (transpose) {
488 | frameWidth = viewHeight;
489 | frameHeight = viewWidth;
490 | } else {
491 | frameWidth = viewWidth;
492 | frameHeight = viewHeight;
493 | }
494 | Camera.Size size = findBestPreviewSize(
495 | // will always return at least one item
496 | parameters.getSupportedPreviewSizes(),
497 | frameWidth,
498 | frameHeight);
499 | parameters.setPreviewSize(size.width, size.height);
500 | }
501 |
502 | private void addSurfaceView(
503 | Context context,
504 | int surfaceWidth,
505 | int surfaceHeight) {
506 | SurfaceView surfaceView = new SurfaceView(context);
507 | SurfaceHolder holder = surfaceView.getHolder();
508 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
509 | holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
510 | }
511 | holder.setKeepScreenOn(true);
512 | holder.addCallback(new SurfaceHolder.Callback() {
513 | @Override
514 | public void surfaceCreated(SurfaceHolder holder) {
515 | // wait until the surface has dimensions
516 | }
517 |
518 | @Override
519 | public void surfaceChanged(
520 | SurfaceHolder holder,
521 | int format,
522 | int width,
523 | int height) {
524 | if (cam == null) {
525 | return;
526 | }
527 | try {
528 | cam.setPreviewDisplay(holder);
529 | } catch (IOException e) {
530 | return;
531 | }
532 | cam.startPreview();
533 | if (cameraListener != null) {
534 | cameraListener.onPreviewStarted(cam);
535 | }
536 | }
537 |
538 | @Override
539 | public void surfaceDestroyed(SurfaceHolder holder) {
540 | close();
541 | }
542 | });
543 | addView(surfaceView);
544 | setChildLayout(
545 | viewWidth,
546 | viewHeight,
547 | surfaceView,
548 | surfaceWidth,
549 | surfaceHeight,
550 | previewRect,
551 | scaleType == SCALE_TYPE_CENTER_INSIDE);
552 | }
553 |
554 | private static void setChildLayout(
555 | int width,
556 | int height,
557 | View child,
558 | int childWidth,
559 | int childHeight,
560 | Rect childRect,
561 | boolean centerInside) {
562 | int widthByHeight = width * childHeight;
563 | int heightByWidth = height * childWidth;
564 | boolean dontScaleBeyondScreen = centerInside ||
565 | Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH;
566 |
567 | if (dontScaleBeyondScreen ?
568 | // center within parent view
569 | widthByHeight > heightByWidth :
570 | // scale to cover parent view
571 | widthByHeight < heightByWidth) {
572 | childWidth = childWidth * height / childHeight;
573 | childHeight = height;
574 | } else {
575 | childHeight = childHeight * width / childWidth;
576 | childWidth = width;
577 | }
578 |
579 | int l = (width - childWidth) >> 1;
580 | int t = dontScaleBeyondScreen ?
581 | (height - childHeight) >> 1 :
582 | 0;
583 |
584 | childRect.set(
585 | l,
586 | t,
587 | l + childWidth,
588 | t + childHeight);
589 |
590 | child.layout(
591 | childRect.left,
592 | childRect.top,
593 | childRect.right,
594 | childRect.bottom);
595 | }
596 | }
597 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markusfisch/CameraView/745597d05bc6abfdb3637a09a8ecaf30fdce7b6e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Jan 26 11:58:22 CET 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':cameraview'
2 |
--------------------------------------------------------------------------------