├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
└── runConfigurations.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── twoeightnine
│ │ └── root
│ │ └── camera
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── twoeightnine
│ │ │ └── root
│ │ │ └── camera
│ │ │ ├── AutoFitTextureView.java
│ │ │ ├── Camera2BasicFragment.java
│ │ │ └── CameraActivity.java
│ └── res
│ │ ├── drawable-hdpi
│ │ ├── ic_action_info.png
│ │ ├── ic_launcher.png
│ │ └── tile.9.png
│ │ ├── drawable-mdpi
│ │ ├── ic_action_info.png
│ │ └── ic_launcher.png
│ │ ├── drawable-xhdpi
│ │ ├── ic_action_info.png
│ │ └── ic_launcher.png
│ │ ├── drawable-xxhdpi
│ │ ├── ic_action_info.png
│ │ └── ic_launcher.png
│ │ ├── drawable
│ │ └── task.jpg
│ │ ├── layout-land
│ │ └── fragment_camera2_basic.xml
│ │ ├── layout
│ │ ├── activity_camera.xml
│ │ └── fragment_camera2_basic.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── values-sw600dp
│ │ ├── template-dimens.xml
│ │ └── template-styles.xml
│ │ ├── values-v11
│ │ └── template-styles.xml
│ │ ├── values-v21
│ │ ├── base-colors.xml
│ │ └── base-template-styles.xml
│ │ └── values
│ │ ├── base-strings.xml
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ ├── styles.xml
│ │ ├── template-dimens.xml
│ │ └── template-styles.xml
│ └── test
│ └── java
│ └── com
│ └── twoeightnine
│ └── root
│ └── camera
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AndroidSpyCamera
2 |
3 | This app shows how you can quietly take photos of app user via front camera. After opening it shows an image with puzzle (its role is to attract attention) while fromt camera takes photos every 2 secs and saves it into ~/Android/data/{appId}/files.
4 |
5 | Basically advantage: app targets on API 22, so you WILL NOT SEE A RUNTIME PERMISSION TO ACCESS CAMERA.
6 |
7 | If you want to protect your privacy:
8 | - trust no one
9 | - close your front camera
10 |
11 | If you want to break someone's privacy:
12 | - add this code to your app
13 | - use encryption to hide fact of capturing
14 | - send all encrypted photos next time user turn on the Internet
15 |
16 | I DO NOT PROPAGANDIZE THIS.
17 | I just want you to know how it is easy to break your privacy!
18 |
19 | This app is based on Camera2Basic repo from Google.
20 |
21 | # Privacy is an illusion
22 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'android-apt'
3 |
4 | android {
5 | compileSdkVersion 22
6 | buildToolsVersion "26.0.1"
7 | defaultConfig {
8 | applicationId "com.twoeightnine.root.camera"
9 | minSdkVersion 21
10 | targetSdkVersion 22
11 | versionCode 1
12 | versionName "1.0"
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | }
22 |
23 | dependencies {
24 | compile fileTree(dir: 'libs', include: ['*.jar'])
25 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
26 | exclude group: 'com.android.support', module: 'support-annotations'
27 | })
28 | compile 'com.android.support:appcompat-v7:22.+'
29 | compile 'com.android.support.constraint:constraint-layout:1.0.2'
30 | testCompile 'junit:junit:4.12'
31 |
32 | compile "com.jakewharton:butterknife:8.5.1"
33 | apt "com.jakewharton:butterknife-compiler:8.5.1"
34 | }
35 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /root/Android/Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/twoeightnine/root/camera/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.twoeightnine.root.camera;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.twoeightnine.root.camera", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
30 |
31 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/twoeightnine/root/camera/AutoFitTextureView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.twoeightnine.root.camera;
18 |
19 | import android.content.Context;
20 | import android.util.AttributeSet;
21 | import android.view.TextureView;
22 |
23 | /**
24 | * A {@link TextureView} that can be adjusted to a specified aspect ratio.
25 | */
26 | public class AutoFitTextureView extends TextureView {
27 |
28 | private int mRatioWidth = 0;
29 | private int mRatioHeight = 0;
30 |
31 | public AutoFitTextureView(Context context) {
32 | this(context, null);
33 | }
34 |
35 | public AutoFitTextureView(Context context, AttributeSet attrs) {
36 | this(context, attrs, 0);
37 | }
38 |
39 | public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {
40 | super(context, attrs, defStyle);
41 | }
42 |
43 | /**
44 | * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
45 | * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
46 | * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
47 | *
48 | * @param width Relative horizontal size
49 | * @param height Relative vertical size
50 | */
51 | public void setAspectRatio(int width, int height) {
52 | if (width < 0 || height < 0) {
53 | throw new IllegalArgumentException("Size cannot be negative.");
54 | }
55 | mRatioWidth = width;
56 | mRatioHeight = height;
57 | requestLayout();
58 | }
59 |
60 | @Override
61 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
62 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
63 | int width = MeasureSpec.getSize(widthMeasureSpec);
64 | int height = MeasureSpec.getSize(heightMeasureSpec);
65 | if (0 == mRatioWidth || 0 == mRatioHeight) {
66 | setMeasuredDimension(width, height);
67 | } else {
68 | if (width < height * mRatioWidth / mRatioHeight) {
69 | setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
70 | } else {
71 | setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
72 | }
73 | }
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/app/src/main/java/com/twoeightnine/root/camera/Camera2BasicFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.twoeightnine.root.camera;
18 |
19 | import android.app.Activity;
20 | import android.app.AlertDialog;
21 | import android.app.Dialog;
22 | import android.content.Context;
23 | import android.content.DialogInterface;
24 | import android.content.res.Configuration;
25 | import android.graphics.ImageFormat;
26 | import android.graphics.Matrix;
27 | import android.graphics.Point;
28 | import android.graphics.RectF;
29 | import android.graphics.SurfaceTexture;
30 | import android.hardware.camera2.CameraAccessException;
31 | import android.hardware.camera2.CameraCaptureSession;
32 | import android.hardware.camera2.CameraCharacteristics;
33 | import android.hardware.camera2.CameraDevice;
34 | import android.hardware.camera2.CameraManager;
35 | import android.hardware.camera2.CameraMetadata;
36 | import android.hardware.camera2.CaptureRequest;
37 | import android.hardware.camera2.CaptureResult;
38 | import android.hardware.camera2.TotalCaptureResult;
39 | import android.hardware.camera2.params.StreamConfigurationMap;
40 | import android.media.Image;
41 | import android.media.ImageReader;
42 | import android.os.Bundle;
43 | import android.os.CountDownTimer;
44 | import android.os.Handler;
45 | import android.os.HandlerThread;
46 | import android.support.annotation.NonNull;
47 | import android.support.annotation.UiThread;
48 | import android.support.v4.app.DialogFragment;
49 | import android.support.v4.app.Fragment;
50 | import android.util.Log;
51 | import android.util.Size;
52 | import android.util.SparseIntArray;
53 | import android.view.LayoutInflater;
54 | import android.view.Surface;
55 | import android.view.TextureView;
56 | import android.view.View;
57 | import android.view.ViewGroup;
58 | import android.widget.TextView;
59 | import android.widget.Toast;
60 |
61 | import java.io.File;
62 | import java.io.FileOutputStream;
63 | import java.io.IOException;
64 | import java.nio.ByteBuffer;
65 | import java.util.ArrayList;
66 | import java.util.Arrays;
67 | import java.util.Collections;
68 | import java.util.Comparator;
69 | import java.util.List;
70 | import java.util.concurrent.Semaphore;
71 | import java.util.concurrent.TimeUnit;
72 |
73 | public class Camera2BasicFragment extends Fragment
74 | implements View.OnClickListener {
75 |
76 | /**
77 | * Conversion from screen rotation to JPEG orientation.
78 | */
79 | private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
80 | private static final int REQUEST_CAMERA_PERMISSION = 1;
81 | private static final String FRAGMENT_DIALOG = "dialog";
82 |
83 | static {
84 | ORIENTATIONS.append(Surface.ROTATION_0, 90);
85 | ORIENTATIONS.append(Surface.ROTATION_90, 0);
86 | ORIENTATIONS.append(Surface.ROTATION_180, 270);
87 | ORIENTATIONS.append(Surface.ROTATION_270, 180);
88 | }
89 |
90 | /**
91 | * Tag for the {@link Log}.
92 | */
93 | private static final String TAG = "Camera2BasicFragment";
94 |
95 | /**
96 | * Camera state: Showing camera preview.
97 | */
98 | private static final int STATE_PREVIEW = 0;
99 |
100 | /**
101 | * Camera state: Waiting for the focus to be locked.
102 | */
103 | private static final int STATE_WAITING_LOCK = 1;
104 |
105 | /**
106 | * Camera state: Waiting for the exposure to be precapture state.
107 | */
108 | private static final int STATE_WAITING_PRECAPTURE = 2;
109 |
110 | /**
111 | * Camera state: Waiting for the exposure state to be something other than precapture.
112 | */
113 | private static final int STATE_WAITING_NON_PRECAPTURE = 3;
114 |
115 | /**
116 | * Camera state: Picture was taken.
117 | */
118 | private static final int STATE_PICTURE_TAKEN = 4;
119 |
120 | /**
121 | * Max preview width that is guaranteed by Camera2 API
122 | */
123 | private static final int MAX_PREVIEW_WIDTH = 1920;
124 |
125 | /**
126 | * Max preview height that is guaranteed by Camera2 API
127 | */
128 | private static final int MAX_PREVIEW_HEIGHT = 1080;
129 |
130 | /**
131 | * {@link TextureView.SurfaceTextureListener} handles several lifecycle events on a
132 | * {@link TextureView}.
133 | */
134 | private final TextureView.SurfaceTextureListener mSurfaceTextureListener
135 | = new TextureView.SurfaceTextureListener() {
136 |
137 | @Override
138 | public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
139 | openCamera(width, height);
140 | }
141 |
142 | @Override
143 | public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
144 | configureTransform(width, height);
145 | }
146 |
147 | @Override
148 | public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
149 | return true;
150 | }
151 |
152 | @Override
153 | public void onSurfaceTextureUpdated(SurfaceTexture texture) {
154 | }
155 |
156 | };
157 |
158 | /**
159 | * ID of the current {@link CameraDevice}.
160 | */
161 | private String mCameraId;
162 |
163 | /**
164 | * An {@link AutoFitTextureView} for camera preview.
165 | */
166 | private AutoFitTextureView mTextureView;
167 |
168 | /**
169 | * A {@link CameraCaptureSession } for camera preview.
170 | */
171 | private CameraCaptureSession mCaptureSession;
172 |
173 | /**
174 | * A reference to the opened {@link CameraDevice}.
175 | */
176 | private CameraDevice mCameraDevice;
177 |
178 | /**
179 | * The {@link android.util.Size} of camera preview.
180 | */
181 | private Size mPreviewSize;
182 |
183 | private int counter = 0;
184 | private TextView tvCounter;
185 |
186 | /**
187 | * {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its state.
188 | */
189 | private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
190 |
191 | @Override
192 | public void onOpened(@NonNull CameraDevice cameraDevice) {
193 | // This method is called when the camera is opened. We start camera preview here.
194 | mCameraOpenCloseLock.release();
195 | mCameraDevice = cameraDevice;
196 | createCameraPreviewSession();
197 | }
198 |
199 | @Override
200 | public void onDisconnected(@NonNull CameraDevice cameraDevice) {
201 | mCameraOpenCloseLock.release();
202 | cameraDevice.close();
203 | mCameraDevice = null;
204 | }
205 |
206 | @Override
207 | public void onError(@NonNull CameraDevice cameraDevice, int error) {
208 | mCameraOpenCloseLock.release();
209 | cameraDevice.close();
210 | mCameraDevice = null;
211 | Activity activity = getActivity();
212 | if (null != activity) {
213 | activity.finish();
214 | }
215 | }
216 |
217 | };
218 |
219 | /**
220 | * An additional thread for running tasks that shouldn't block the UI.
221 | */
222 | private HandlerThread mBackgroundThread;
223 |
224 | /**
225 | * A {@link Handler} for running tasks in the background.
226 | */
227 | private Handler mBackgroundHandler;
228 |
229 | /**
230 | * An {@link ImageReader} that handles still image capture.
231 | */
232 | private ImageReader mImageReader;
233 |
234 | /**
235 | * This is the output file for our picture.
236 | */
237 | private File mFile;
238 |
239 | /**
240 | * This a callback object for the {@link ImageReader}. "onImageAvailable" will be called when a
241 | * still image is ready to be saved.
242 | */
243 | private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
244 | = new ImageReader.OnImageAvailableListener() {
245 |
246 | @Override
247 | public void onImageAvailable(ImageReader reader) {
248 | mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile, getActivity()));
249 | }
250 |
251 | };
252 |
253 | /**
254 | * {@link CaptureRequest.Builder} for the camera preview
255 | */
256 | private CaptureRequest.Builder mPreviewRequestBuilder;
257 |
258 | /**
259 | * {@link CaptureRequest} generated by {@link #mPreviewRequestBuilder}
260 | */
261 | private CaptureRequest mPreviewRequest;
262 |
263 | /**
264 | * The current state of camera state for taking pictures.
265 | *
266 | * @see #mCaptureCallback
267 | */
268 | private int mState = STATE_PREVIEW;
269 |
270 | /**
271 | * A {@link Semaphore} to prevent the app from exiting before closing the camera.
272 | */
273 | private Semaphore mCameraOpenCloseLock = new Semaphore(1);
274 |
275 | /**
276 | * Whether the current camera device supports Flash or not.
277 | */
278 | private boolean mFlashSupported;
279 |
280 | /**
281 | * Orientation of the camera sensor
282 | */
283 | private int mSensorOrientation;
284 |
285 | /**
286 | * A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture.
287 | */
288 | private CameraCaptureSession.CaptureCallback mCaptureCallback
289 | = new CameraCaptureSession.CaptureCallback() {
290 |
291 | private void process(CaptureResult result) {
292 | switch (mState) {
293 | case STATE_PREVIEW: {
294 | // We have nothing to do when the camera preview is working normally.
295 | break;
296 | }
297 | case STATE_WAITING_LOCK: {
298 | Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
299 | if (afState == null) {
300 | captureStillPicture();
301 | } else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
302 | CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
303 | // CONTROL_AE_STATE can be null on some devices
304 | Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
305 | if (aeState == null ||
306 | aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
307 | mState = STATE_PICTURE_TAKEN;
308 | captureStillPicture();
309 | } else {
310 | runPrecaptureSequence();
311 | }
312 | } else {
313 | captureStillPicture();
314 | }
315 | break;
316 | }
317 | case STATE_WAITING_PRECAPTURE: {
318 | // CONTROL_AE_STATE can be null on some devices
319 | Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
320 | if (aeState == null ||
321 | aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
322 | aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
323 | mState = STATE_WAITING_NON_PRECAPTURE;
324 | }
325 | break;
326 | }
327 | case STATE_WAITING_NON_PRECAPTURE: {
328 | // CONTROL_AE_STATE can be null on some devices
329 | Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
330 | if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
331 | mState = STATE_PICTURE_TAKEN;
332 | captureStillPicture();
333 | }
334 | break;
335 | }
336 | }
337 | }
338 |
339 | @Override
340 | public void onCaptureProgressed(@NonNull CameraCaptureSession session,
341 | @NonNull CaptureRequest request,
342 | @NonNull CaptureResult partialResult) {
343 | process(partialResult);
344 | }
345 |
346 | @Override
347 | public void onCaptureCompleted(@NonNull CameraCaptureSession session,
348 | @NonNull CaptureRequest request,
349 | @NonNull TotalCaptureResult result) {
350 | process(result);
351 | }
352 |
353 | };
354 |
355 | /**
356 | * Shows a {@link Toast} on the UI thread.
357 | *
358 | * @param text The message to show
359 | */
360 | private void showToast(final String text) {
361 | final Activity activity = getActivity();
362 | if (activity != null) {
363 | activity.runOnUiThread(new Runnable() {
364 | @Override
365 | public void run() {
366 | Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();
367 | }
368 | });
369 | }
370 | }
371 |
372 | /**
373 | * Given {@code choices} of {@code Size}s supported by a camera, choose the smallest one that
374 | * is at least as large as the respective texture view size, and that is at most as large as the
375 | * respective max size, and whose aspect ratio matches with the specified value. If such size
376 | * doesn't exist, choose the largest one that is at most as large as the respective max size,
377 | * and whose aspect ratio matches with the specified value.
378 | *
379 | * @param choices The list of sizes that the camera supports for the intended output
380 | * class
381 | * @param textureViewWidth The width of the texture view relative to sensor coordinate
382 | * @param textureViewHeight The height of the texture view relative to sensor coordinate
383 | * @param maxWidth The maximum width that can be chosen
384 | * @param maxHeight The maximum height that can be chosen
385 | * @param aspectRatio The aspect ratio
386 | * @return The optimal {@code Size}, or an arbitrary one if none were big enough
387 | */
388 | private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,
389 | int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {
390 |
391 | // Collect the supported resolutions that are at least as big as the preview Surface
392 | List bigEnough = new ArrayList<>();
393 | // Collect the supported resolutions that are smaller than the preview Surface
394 | List notBigEnough = new ArrayList<>();
395 | int w = aspectRatio.getWidth();
396 | int h = aspectRatio.getHeight();
397 | for (Size option : choices) {
398 | if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
399 | option.getHeight() == option.getWidth() * h / w) {
400 | if (option.getWidth() >= textureViewWidth &&
401 | option.getHeight() >= textureViewHeight) {
402 | bigEnough.add(option);
403 | } else {
404 | notBigEnough.add(option);
405 | }
406 | }
407 | }
408 |
409 | // Pick the smallest of those big enough. If there is no one big enough, pick the
410 | // largest of those not big enough.
411 | if (bigEnough.size() > 0) {
412 | return Collections.min(bigEnough, new CompareSizesByArea());
413 | } else if (notBigEnough.size() > 0) {
414 | return Collections.max(notBigEnough, new CompareSizesByArea());
415 | } else {
416 | Log.e(TAG, "Couldn't find any suitable preview size");
417 | return choices[0];
418 | }
419 | }
420 |
421 | public static Camera2BasicFragment newInstance() {
422 | return new Camera2BasicFragment();
423 | }
424 |
425 | @Override
426 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
427 | Bundle savedInstanceState) {
428 | return inflater.inflate(R.layout.fragment_camera2_basic, container, false);
429 | }
430 |
431 | @Override
432 | public void onViewCreated(final View view, Bundle savedInstanceState) {
433 | final View picture = view.findViewById(R.id.picture);
434 | picture.setOnClickListener(this);
435 | view.findViewById(R.id.info).setOnClickListener(this);
436 | mTextureView = (AutoFitTextureView) view.findViewById(R.id.texture);
437 | tvCounter = (TextView) view.findViewById(R.id.tvCounter);
438 |
439 | final Runnable runnable = new Object() {
440 | final Runnable runnable = new Runnable() {
441 | @Override
442 | public void run() {
443 | new CountDownTimer(2000, 2000) {
444 | @Override
445 | public void onTick(long millisUntilFinished) {}
446 |
447 | @Override
448 | public void onFinish() {
449 | takePicture();
450 | runnable.run();
451 | }
452 | }.start();
453 | }
454 | };
455 | }.runnable;
456 | new CountDownTimer(2000, 2000) {
457 | @Override
458 | public void onTick(long millisUntilFinished) {}
459 |
460 | @Override
461 | public void onFinish() {
462 | runnable.run();
463 | }
464 | }.start();
465 | }
466 |
467 | @Override
468 | public void onActivityCreated(Bundle savedInstanceState) {
469 | super.onActivityCreated(savedInstanceState);
470 | // mFileDir = getActivity().getExternalFilesDir(null);
471 | mFile = new File(getActivity().getExternalFilesDir(null), "pic.jpg");
472 | }
473 |
474 | @Override
475 | public void onResume() {
476 | super.onResume();
477 | startBackgroundThread();
478 |
479 | // When the screen is turned off and turned back on, the SurfaceTexture is already
480 | // available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
481 | // a camera and start preview from here (otherwise, we wait until the surface is ready in
482 | // the SurfaceTextureListener).
483 | if (mTextureView.isAvailable()) {
484 | openCamera(mTextureView.getWidth(), mTextureView.getHeight());
485 | } else {
486 | mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
487 | }
488 | }
489 |
490 | @Override
491 | public void onPause() {
492 | closeCamera();
493 | stopBackgroundThread();
494 | super.onPause();
495 | }
496 |
497 | /**
498 | * Sets up member variables related to camera.
499 | *
500 | * @param width The width of available size for camera preview
501 | * @param height The height of available size for camera preview
502 | */
503 | @SuppressWarnings("SuspiciousNameCombination")
504 | private void setUpCameraOutputs(int width, int height) {
505 | Activity activity = getActivity();
506 | CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
507 | try {
508 | String[] cameraIds = manager.getCameraIdList();
509 | // for (String s : cameraIds) {
510 | // Log.i("qwer", "" + s);
511 | // }
512 | for (String cameraId : cameraIds) {
513 | Log.i("qwer", "cameId=" + cameraId);
514 | CameraCharacteristics characteristics
515 | = manager.getCameraCharacteristics(cameraId);
516 |
517 | // We don't use a front facing camera in this sample.
518 | Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
519 | Log.i("qwer", "fac=" + facing);
520 | if (facing != null && facing == CameraCharacteristics.LENS_FACING_BACK) {
521 | Log.i("qwer", "cont fac " + facing);
522 | continue;
523 | }
524 |
525 | StreamConfigurationMap map = characteristics.get(
526 | CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
527 | if (map == null) {
528 | Log.i("qwer", "map null");
529 | continue;
530 | }
531 |
532 | // For still image captures, we use the largest available size.
533 | Size largest = Collections.max(
534 | Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
535 | new CompareSizesByArea());
536 | mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),
537 | ImageFormat.JPEG, /*maxImages*/2);
538 | mImageReader.setOnImageAvailableListener(
539 | mOnImageAvailableListener, mBackgroundHandler);
540 |
541 | // Find out if we need to swap dimension to get the preview size relative to sensor
542 | // coordinate.
543 | int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
544 | //noinspection ConstantConditions
545 | mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
546 | boolean swappedDimensions = false;
547 | switch (displayRotation) {
548 | case Surface.ROTATION_0:
549 | case Surface.ROTATION_180:
550 | if (mSensorOrientation == 90 || mSensorOrientation == 270) {
551 | swappedDimensions = true;
552 | }
553 | break;
554 | case Surface.ROTATION_90:
555 | case Surface.ROTATION_270:
556 | if (mSensorOrientation == 0 || mSensorOrientation == 180) {
557 | swappedDimensions = true;
558 | }
559 | break;
560 | default:
561 | Log.e(TAG, "Display rotation is invalid: " + displayRotation);
562 | }
563 |
564 | Point displaySize = new Point();
565 | activity.getWindowManager().getDefaultDisplay().getSize(displaySize);
566 | int rotatedPreviewWidth = width;
567 | int rotatedPreviewHeight = height;
568 | int maxPreviewWidth = displaySize.x;
569 | int maxPreviewHeight = displaySize.y;
570 |
571 | if (swappedDimensions) {
572 | rotatedPreviewWidth = height;
573 | rotatedPreviewHeight = width;
574 | maxPreviewWidth = displaySize.y;
575 | maxPreviewHeight = displaySize.x;
576 | }
577 |
578 | if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
579 | maxPreviewWidth = MAX_PREVIEW_WIDTH;
580 | }
581 |
582 | if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
583 | maxPreviewHeight = MAX_PREVIEW_HEIGHT;
584 | }
585 |
586 | // Danger, W.R.! Attempting to use too large a preview size could exceed the camera
587 | // bus' bandwidth limitation, resulting in gorgeous previews but the storage of
588 | // garbage capture data.
589 | mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
590 | rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
591 | maxPreviewHeight, largest);
592 |
593 | // We fit the aspect ratio of TextureView to the size of preview we picked.
594 | int orientation = getResources().getConfiguration().orientation;
595 | if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
596 | mTextureView.setAspectRatio(
597 | mPreviewSize.getWidth(), mPreviewSize.getHeight());
598 | } else {
599 | mTextureView.setAspectRatio(
600 | mPreviewSize.getHeight(), mPreviewSize.getWidth());
601 | }
602 |
603 | // Check if the flash is supported.
604 | Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
605 | mFlashSupported = available == null ? false : available;
606 |
607 | mCameraId = cameraId;
608 | Log.i("qwer", "cam id " + mCameraId);
609 | return;
610 | }
611 | } catch (CameraAccessException e) {
612 | e.printStackTrace();
613 | } catch (NullPointerException e) {
614 | // Currently an NPE is thrown when the Camera2API is used but not supported on the
615 | // device this code runs.
616 | ErrorDialog.newInstance(getString(R.string.camera_error))
617 | .show(getChildFragmentManager(), FRAGMENT_DIALOG);
618 | }
619 | }
620 |
621 | /**
622 | * Opens the camera specified by {@link Camera2BasicFragment#mCameraId}.
623 | */
624 | private void openCamera(int width, int height) {
625 | setUpCameraOutputs(width, height);
626 | configureTransform(width, height);
627 | Activity activity = getActivity();
628 | CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
629 | try {
630 | if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
631 | throw new RuntimeException("Time out waiting to lock camera opening.");
632 | }
633 | Log.i("qwer", "camId cr " + mCameraId);
634 | manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
635 | } catch (CameraAccessException e) {
636 | e.printStackTrace();
637 | } catch (InterruptedException e) {
638 | throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
639 | }
640 | }
641 |
642 | /**
643 | * Closes the current {@link CameraDevice}.
644 | */
645 | private void closeCamera() {
646 | try {
647 | mCameraOpenCloseLock.acquire();
648 | if (null != mCaptureSession) {
649 | mCaptureSession.close();
650 | mCaptureSession = null;
651 | }
652 | if (null != mCameraDevice) {
653 | mCameraDevice.close();
654 | mCameraDevice = null;
655 | }
656 | if (null != mImageReader) {
657 | mImageReader.close();
658 | mImageReader = null;
659 | }
660 | } catch (InterruptedException e) {
661 | throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
662 | } finally {
663 | mCameraOpenCloseLock.release();
664 | }
665 | }
666 |
667 | /**
668 | * Starts a background thread and its {@link Handler}.
669 | */
670 | private void startBackgroundThread() {
671 | mBackgroundThread = new HandlerThread("CameraBackground");
672 | mBackgroundThread.start();
673 | mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
674 | }
675 |
676 | /**
677 | * Stops the background thread and its {@link Handler}.
678 | */
679 | private void stopBackgroundThread() {
680 | mBackgroundThread.quitSafely();
681 | try {
682 | mBackgroundThread.join();
683 | mBackgroundThread = null;
684 | mBackgroundHandler = null;
685 | } catch (InterruptedException e) {
686 | e.printStackTrace();
687 | }
688 | }
689 |
690 | /**
691 | * Creates a new {@link CameraCaptureSession} for camera preview.
692 | */
693 | private void createCameraPreviewSession() {
694 | try {
695 | SurfaceTexture texture = mTextureView.getSurfaceTexture();
696 | assert texture != null;
697 |
698 | // We configure the size of default buffer to be the size of camera preview we want.
699 | texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
700 |
701 | // This is the output Surface we need to start preview.
702 | Surface surface = new Surface(texture);
703 |
704 | // We set up a CaptureRequest.Builder with the output Surface.
705 | mPreviewRequestBuilder
706 | = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
707 | mPreviewRequestBuilder.addTarget(surface);
708 |
709 | // Here, we create a CameraCaptureSession for camera preview.
710 | mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
711 | new CameraCaptureSession.StateCallback() {
712 |
713 | @Override
714 | public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
715 | // The camera is already closed
716 | if (null == mCameraDevice) {
717 | return;
718 | }
719 |
720 | // When the session is ready, we start displaying the preview.
721 | mCaptureSession = cameraCaptureSession;
722 | try {
723 | // Auto focus should be continuous for camera preview.
724 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
725 | CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
726 | // Flash is automatically enabled when necessary.
727 | setAutoFlash(mPreviewRequestBuilder);
728 |
729 | // Finally, we start displaying the camera preview.
730 | mPreviewRequest = mPreviewRequestBuilder.build();
731 | mCaptureSession.setRepeatingRequest(mPreviewRequest,
732 | mCaptureCallback, mBackgroundHandler);
733 | } catch (CameraAccessException e) {
734 | e.printStackTrace();
735 | }
736 | }
737 |
738 | @Override
739 | public void onConfigureFailed(
740 | @NonNull CameraCaptureSession cameraCaptureSession) {
741 | showToast("Failed");
742 | }
743 | }, null
744 | );
745 | } catch (CameraAccessException e) {
746 | e.printStackTrace();
747 | }
748 | }
749 |
750 | /**
751 | * Configures the necessary {@link android.graphics.Matrix} transformation to `mTextureView`.
752 | * This method should be called after the camera preview size is determined in
753 | * setUpCameraOutputs and also the size of `mTextureView` is fixed.
754 | *
755 | * @param viewWidth The width of `mTextureView`
756 | * @param viewHeight The height of `mTextureView`
757 | */
758 | private void configureTransform(int viewWidth, int viewHeight) {
759 | Activity activity = getActivity();
760 | if (null == mTextureView || null == mPreviewSize || null == activity) {
761 | return;
762 | }
763 | int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
764 | Matrix matrix = new Matrix();
765 | RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
766 | RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
767 | float centerX = viewRect.centerX();
768 | float centerY = viewRect.centerY();
769 | if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
770 | bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
771 | matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
772 | float scale = Math.max(
773 | (float) viewHeight / mPreviewSize.getHeight(),
774 | (float) viewWidth / mPreviewSize.getWidth());
775 | matrix.postScale(scale, scale, centerX, centerY);
776 | matrix.postRotate(90 * (rotation - 2), centerX, centerY);
777 | } else if (Surface.ROTATION_180 == rotation) {
778 | matrix.postRotate(180, centerX, centerY);
779 | }
780 | mTextureView.setTransform(matrix);
781 | }
782 |
783 | /**
784 | * Initiate a still image capture.
785 | */
786 | private void takePicture() {
787 | lockFocus();
788 | }
789 |
790 | /**
791 | * Lock the focus as the first step for a still image capture.
792 | */
793 | private void lockFocus() {
794 | try {
795 | // This is how to tell the camera to lock focus.
796 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
797 | CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
798 | // Tell #mCaptureCallback to wait for the lock.
799 | mState = STATE_WAITING_LOCK;
800 | mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
801 | mBackgroundHandler);
802 | } catch (CameraAccessException e) {
803 | e.printStackTrace();
804 | }
805 | }
806 |
807 | /**
808 | * Run the precapture sequence for capturing a still image. This method should be called when
809 | * we get a response in {@link #mCaptureCallback} from {@link #lockFocus()}.
810 | */
811 | private void runPrecaptureSequence() {
812 | try {
813 | // This is how to tell the camera to trigger.
814 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
815 | CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
816 | // Tell #mCaptureCallback to wait for the precapture sequence to be set.
817 | mState = STATE_WAITING_PRECAPTURE;
818 | mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
819 | mBackgroundHandler);
820 | } catch (CameraAccessException e) {
821 | e.printStackTrace();
822 | }
823 | }
824 |
825 | /**
826 | * Capture a still picture. This method should be called when we get a response in
827 | * {@link #mCaptureCallback} from both {@link #lockFocus()}.
828 | */
829 | private void captureStillPicture() {
830 | try {
831 | final Activity activity = getActivity();
832 | if (null == activity || null == mCameraDevice) {
833 | return;
834 | }
835 | // This is the CaptureRequest.Builder that we use to take a picture.
836 | final CaptureRequest.Builder captureBuilder =
837 | mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
838 | captureBuilder.addTarget(mImageReader.getSurface());
839 |
840 | // Use the same AE and AF modes as the preview.
841 | captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
842 | CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
843 | setAutoFlash(captureBuilder);
844 |
845 | // Orientation
846 | int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
847 | captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
848 |
849 | CameraCaptureSession.CaptureCallback CaptureCallback
850 | = new CameraCaptureSession.CaptureCallback() {
851 |
852 | @Override
853 | public void onCaptureCompleted(@NonNull CameraCaptureSession session,
854 | @NonNull CaptureRequest request,
855 | @NonNull TotalCaptureResult result) {
856 | // showToast("Saved: " + mFile);
857 | counter++;
858 | getActivity().runOnUiThread(new Runnable() {
859 | @Override
860 | public void run() {
861 | updateCounter();
862 | }
863 | });
864 | Log.d(TAG, mFile.toString());
865 | unlockFocus();
866 | }
867 | };
868 |
869 | mCaptureSession.stopRepeating();
870 | mCaptureSession.abortCaptures();
871 | mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
872 | } catch (CameraAccessException e) {
873 | e.printStackTrace();
874 | }
875 | }
876 |
877 | @UiThread
878 | private void updateCounter() {
879 | tvCounter.setText("" + counter);
880 | }
881 |
882 | /**
883 | * Retrieves the JPEG orientation from the specified screen rotation.
884 | *
885 | * @param rotation The screen rotation.
886 | * @return The JPEG orientation (one of 0, 90, 270, and 360)
887 | */
888 | private int getOrientation(int rotation) {
889 | // Sensor orientation is 90 for most devices, or 270 for some devices (eg. Nexus 5X)
890 | // We have to take that into account and rotate JPEG properly.
891 | // For devices with orientation of 90, we simply return our mapping from ORIENTATIONS.
892 | // For devices with orientation of 270, we need to rotate the JPEG 180 degrees.
893 | return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;
894 | }
895 |
896 | /**
897 | * Unlock the focus. This method should be called when still image capture sequence is
898 | * finished.
899 | */
900 | private void unlockFocus() {
901 | try {
902 | // Reset the auto-focus trigger
903 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
904 | CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
905 | setAutoFlash(mPreviewRequestBuilder);
906 | mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
907 | mBackgroundHandler);
908 | // After this, the camera will go back to the normal state of preview.
909 | mState = STATE_PREVIEW;
910 | mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,
911 | mBackgroundHandler);
912 | } catch (CameraAccessException e) {
913 | e.printStackTrace();
914 | }
915 | }
916 |
917 | @Override
918 | public void onClick(View view) {
919 | switch (view.getId()) {
920 | case R.id.picture: {
921 | takePicture();
922 | break;
923 | }
924 | case R.id.info: {
925 | Activity activity = getActivity();
926 | if (null != activity) {
927 | new AlertDialog.Builder(activity)
928 | .setMessage(R.string.intro_message)
929 | .setPositiveButton(android.R.string.ok, null)
930 | .show();
931 | }
932 | break;
933 | }
934 | }
935 | }
936 |
937 | private void setAutoFlash(CaptureRequest.Builder requestBuilder) {
938 | if (mFlashSupported && false) {
939 | requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
940 | CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
941 | }
942 | }
943 |
944 | /**
945 | * Saves a JPEG {@link Image} into the specified {@link File}.
946 | */
947 | private static class ImageSaver implements Runnable {
948 |
949 | /**
950 | * The JPEG image
951 | */
952 | private final Image mImage;
953 | /**
954 | * The file we save the image into.
955 | */
956 | private File mFile;
957 |
958 | private final Context mContext;
959 |
960 | ImageSaver(Image image, File file, Context context) {
961 | mImage = image;
962 | mFile = file;
963 | mContext = context;
964 | }
965 |
966 | @Override
967 | public void run() {
968 | ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
969 | byte[] bytes = new byte[buffer.remaining()];
970 | buffer.get(bytes);
971 | FileOutputStream output = null;
972 | mFile = getFileName();
973 | try {
974 | output = new FileOutputStream(mFile);
975 | output.write(bytes);
976 | } catch (IOException e) {
977 | e.printStackTrace();
978 | } finally {
979 | mImage.close();
980 | if (null != output) {
981 | try {
982 | output.close();
983 | } catch (IOException e) {
984 | e.printStackTrace();
985 | }
986 | }
987 | }
988 | }
989 |
990 | private File getFileName() {
991 | return new File(mContext.getExternalFilesDir(null), "pic" + System.currentTimeMillis() + ".jpg");
992 | }
993 |
994 | }
995 |
996 | /**
997 | * Compares two {@code Size}s based on their areas.
998 | */
999 | static class CompareSizesByArea implements Comparator {
1000 |
1001 | @Override
1002 | public int compare(Size lhs, Size rhs) {
1003 | // We cast here to ensure the multiplications won't overflow
1004 | return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
1005 | (long) rhs.getWidth() * rhs.getHeight());
1006 | }
1007 |
1008 | }
1009 |
1010 | /**
1011 | * Shows an error message dialog.
1012 | */
1013 | public static class ErrorDialog extends DialogFragment {
1014 |
1015 | private static final String ARG_MESSAGE = "message";
1016 |
1017 | public static ErrorDialog newInstance(String message) {
1018 | ErrorDialog dialog = new ErrorDialog();
1019 | Bundle args = new Bundle();
1020 | args.putString(ARG_MESSAGE, message);
1021 | dialog.setArguments(args);
1022 | return dialog;
1023 | }
1024 |
1025 | @NonNull
1026 | @Override
1027 | public Dialog onCreateDialog(Bundle savedInstanceState) {
1028 | final Activity activity = getActivity();
1029 | return new AlertDialog.Builder(activity)
1030 | .setMessage(getArguments().getString(ARG_MESSAGE))
1031 | .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
1032 | @Override
1033 | public void onClick(DialogInterface dialogInterface, int i) {
1034 | activity.finish();
1035 | }
1036 | })
1037 | .create();
1038 | }
1039 |
1040 | }
1041 |
1042 | }
1043 |
--------------------------------------------------------------------------------
/app/src/main/java/com/twoeightnine/root/camera/CameraActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.twoeightnine.root.camera;
18 |
19 | import android.os.Bundle;
20 | import android.support.v7.app.AppCompatActivity;
21 |
22 | public class CameraActivity extends AppCompatActivity {
23 |
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | setContentView(R.layout.activity_camera);
28 | if (null == savedInstanceState) {
29 | getSupportFragmentManager().beginTransaction()
30 | .replace(R.id.container, Camera2BasicFragment.newInstance())
31 | .commit();
32 | }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/drawable-hdpi/ic_action_info.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/tile.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/drawable-hdpi/tile.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/drawable-mdpi/ic_action_info.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/drawable-xhdpi/ic_action_info.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_action_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/drawable-xxhdpi/ic_action_info.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/task.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/drawable/task.jpg
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/fragment_camera2_basic.xml:
--------------------------------------------------------------------------------
1 |
16 |
19 |
20 |
27 |
28 |
38 |
39 |
45 |
46 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_camera.xml:
--------------------------------------------------------------------------------
1 |
16 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_camera2_basic.xml:
--------------------------------------------------------------------------------
1 |
16 |
19 |
20 |
26 |
27 |
34 |
35 |
41 |
42 |
51 |
52 |
53 |
54 |
58 |
59 |
63 |
64 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values-sw600dp/template-dimens.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 | @dimen/margin_huge
22 | @dimen/margin_medium
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/values-sw600dp/template-styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v11/template-styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/base-colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/base-template-styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/values/base-strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | Camera2Basic
20 |
21 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | #cc4285f4
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 | Picture
18 | Info
19 | This sample needs camera permission.
20 | This device doesn\'t support Camera2 API.
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/values/template-dimens.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 | 4dp
22 | 8dp
23 | 16dp
24 | 32dp
25 | 64dp
26 |
27 |
28 |
29 | @dimen/margin_medium
30 | @dimen/margin_medium
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/values/template-styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
34 |
35 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/test/java/com/twoeightnine/root/camera/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.twoeightnine.root.camera;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.3.0'
9 | classpath "com.neenbedankt.gradle.plugins:android-apt:1.8"
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | }
20 | }
21 |
22 | task clean(type: Delete) {
23 | delete rootProject.buildDir
24 | }
25 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwoEightNine/AndroidSpyCamera/abee050efb63d9bcd75a63973139af7802624642/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Oct 21 17:06:11 SAMT 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------