├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── 1.jpg
├── README.md
├── apk
└── CustomCamera.apk
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── ysq
│ │ └── customcamera
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── ysq
│ │ │ └── customcamera
│ │ │ ├── CameraActivity.java
│ │ │ ├── CameraUtil.java
│ │ │ ├── DefaultSubscriber.java
│ │ │ └── MainActivity.java
│ └── res
│ │ ├── drawable-xxhdpi
│ │ ├── camera_back.png
│ │ ├── camera_flash_auto.png
│ │ ├── camera_flash_off.png
│ │ ├── camera_flash_on.png
│ │ ├── camera_flip.png
│ │ ├── camera_library.png
│ │ └── camera_photo.png
│ │ ├── drawable
│ │ ├── btn_take_photo.xml
│ │ └── cam_focus.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ └── activity_test_camera.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── ysq
│ └── customcamera
│ └── 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 | Android
39 |
40 |
41 | Android > Lint > Correctness
42 |
43 |
44 | Android > Lint > Internationalization
45 |
46 |
47 | Android > Lint > Security
48 |
49 |
50 | CorrectnessLintAndroid
51 |
52 |
53 | Gradle
54 |
55 |
56 | LintAndroid
57 |
58 |
59 | Probable bugsGradle
60 |
61 |
62 |
63 |
64 | Android
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | 1.8
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/1.jpg
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CustomCamera
2 | 自定义相机,有聚焦、闪光灯、以及连续拍照、查看等功能
3 |
4 | 
5 |
6 | ###Camera控制拍照的过程
7 |
8 | 调用Camera的open()方法打开相机。
9 |
10 | 调用Camera的getParameters()获取拍照参数,该方法返回一个Cmera.Parameters对象。
11 |
12 | 调用Camera.Parameters对象对照相的参数进行设置。
13 |
14 | 调用Camera的setParameters(),并将Camera.Parameters对象作为参数传入,这样就可以对拍照进行参数控制,Android2.3.3以后不用设置。
15 |
16 | 调用Camerade的startPreview()的方法开始预览取景,在之前需要调用Camera的setPreviewDisplay(SurfaceHolder holder)设置使用哪个SurfaceView来显示取得的图片。
17 |
18 | 调用Camera的takePicture()方法进行拍照。
19 |
20 | 程序结束时,要调用Camera的stopPreview()方法停止预览,并且通过Camera.release()来释放资源。
21 |
22 |
23 | **[DownLoad Apk](https://github.com/ysq1051838264/CustomCamera/blob/master/apk/CustomCamera.apk?raw=true)**
24 |
--------------------------------------------------------------------------------
/apk/CustomCamera.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/apk/CustomCamera.apk
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 24
5 | buildToolsVersion "24.0.2"
6 | defaultConfig {
7 | applicationId "com.example.ysq.customcamera"
8 | minSdkVersion 18
9 | targetSdkVersion 24
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 |
25 | compile ('com.tbruyelle.rxpermissions:rxpermissions:0.7.0@aar')
26 | compile ('com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4')
27 |
28 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
29 | exclude group: 'com.android.support', module: 'support-annotations'
30 | })
31 | compile 'com.android.support:appcompat-v7:24.2.1'
32 | testCompile 'junit:junit:4.12'
33 | }
34 |
--------------------------------------------------------------------------------
/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 /Volumes/ms/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 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/ysq/customcamera/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.ysq.customcamera;
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.example.ysq.customcamera", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/ysq/customcamera/CameraActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.ysq.customcamera;
2 |
3 | import android.Manifest;
4 | import android.content.Context;
5 | import android.content.DialogInterface;
6 | import android.content.Intent;
7 | import android.graphics.Bitmap;
8 | import android.graphics.BitmapFactory;
9 | import android.graphics.Matrix;
10 | import android.graphics.Rect;
11 | import android.hardware.Camera;
12 | import android.net.Uri;
13 | import android.os.Build;
14 | import android.os.Bundle;
15 | import android.os.Environment;
16 | import android.os.Handler;
17 | import android.provider.MediaStore;
18 | import android.provider.Settings;
19 | import android.support.annotation.Nullable;
20 | import android.support.v7.app.AlertDialog;
21 | import android.support.v7.app.AppCompatActivity;
22 | import android.util.Log;
23 | import android.view.MotionEvent;
24 | import android.view.SurfaceHolder;
25 | import android.view.SurfaceView;
26 | import android.view.View;
27 | import android.view.animation.ScaleAnimation;
28 | import android.widget.Button;
29 | import android.widget.FrameLayout;
30 | import android.widget.ImageButton;
31 | import android.widget.ImageView;
32 | import android.widget.RelativeLayout;
33 | import android.widget.Toast;
34 |
35 | import com.tbruyelle.rxpermissions.Permission;
36 | import com.tbruyelle.rxpermissions.RxPermissions;
37 |
38 | import java.io.File;
39 | import java.io.FileNotFoundException;
40 | import java.io.FileOutputStream;
41 | import java.io.IOException;
42 | import java.util.ArrayList;
43 | import java.util.List;
44 |
45 | public class CameraActivity extends AppCompatActivity implements SurfaceHolder.Callback, View.OnClickListener {
46 | private Camera mCamera;
47 | private int cameraPosition = 0;//0代表前置摄像头,1代表后置摄像头,默认打开前置摄像头
48 | SurfaceHolder holder;
49 |
50 | SurfaceView mSurfaceView;
51 | ImageButton openLight;
52 | View focusIndex;
53 | View bootomRly;
54 |
55 | private float pointX, pointY;
56 | static final int FOCUS = 1; // 聚焦
57 | static final int ZOOM = 2; // 缩放
58 | private int mode; //0是聚焦 1是放大
59 | //放大缩小
60 | int curZoomValue = 0;
61 | private float dist;
62 | Camera.Parameters parameters;
63 | private Handler handler = new Handler();
64 | boolean safeToTakePicture = true;
65 | RxPermissions rxPermissions;
66 |
67 | /* 图像数据处理完成后的回调函数 */
68 | private Camera.PictureCallback mJpeg = new Camera.PictureCallback() {
69 | @Override
70 | public void onPictureTaken(final byte[] data, Camera camera) {
71 | new Thread(new Runnable() {
72 | @Override
73 | public void run() {
74 | try {
75 | //将照片改为竖直方向
76 | Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
77 | Matrix matrix = new Matrix();
78 | switch (cameraPosition) {
79 | case 0://前
80 | matrix.preRotate(90);
81 | break;
82 | case 1:
83 | matrix.preRotate(90);
84 | break;
85 | }
86 | bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
87 | saveImageToGallery(getBaseContext(), bitmap);
88 |
89 | mCamera.stopPreview();
90 | mCamera.startPreview();
91 |
92 | } catch (Exception e) {
93 | e.printStackTrace();
94 | }
95 |
96 | safeToTakePicture = true;
97 | }
98 | }).start();
99 | }
100 | };
101 |
102 | @Override
103 | protected void onCreate(@Nullable Bundle savedInstanceState) {
104 | super.onCreate(savedInstanceState);
105 | setContentView(R.layout.activity_test_camera);
106 | CameraUtil.init(this);
107 |
108 | initView();
109 |
110 | initData();
111 | }
112 |
113 | private void initView() {
114 | rxPermissions = RxPermissions.getInstance(this);
115 |
116 | mSurfaceView = (SurfaceView) findViewById(R.id.my_surfaceView);
117 | openLight = (ImageButton) findViewById(R.id.openLight);
118 | focusIndex = findViewById(R.id.focus_index);
119 | bootomRly = findViewById(R.id.bootomRly);
120 |
121 | ImageView image1 = (ImageView) findViewById(R.id.back);
122 | ImageView next = (ImageView) findViewById(R.id.lookPictureIv);
123 | Button button = (Button) findViewById(R.id.takePhoto);
124 | ImageButton imageButton2 = (ImageButton) findViewById(R.id.cameraSwitch);
125 |
126 | image1.setOnClickListener(this);
127 | next.setOnClickListener(this);
128 | button.setOnClickListener(this);
129 | openLight.setOnClickListener(this);
130 | imageButton2.setOnClickListener(this);
131 | }
132 |
133 | protected void initData() {
134 | holder = mSurfaceView.getHolder();
135 | holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
136 | holder.addCallback(this); // 回调接口
137 |
138 | bootomRly.setOnClickListener(new View.OnClickListener() {
139 | @Override
140 | public void onClick(View v) {
141 | }
142 | });
143 |
144 | mSurfaceView.setOnTouchListener(new View.OnTouchListener() {
145 | @Override
146 | public boolean onTouch(View v, MotionEvent event) {
147 | switch (event.getAction() & MotionEvent.ACTION_MASK) {
148 | // 主点按下
149 | case MotionEvent.ACTION_DOWN:
150 | pointX = event.getX();
151 | pointY = event.getY();
152 | mode = FOCUS;
153 | break;
154 | // 副点按下
155 | case MotionEvent.ACTION_POINTER_DOWN:
156 | dist = spacing(event);
157 | // 如果连续两点距离大于10,则判定为多点模式
158 | if (spacing(event) > 10f) {
159 | mode = ZOOM;
160 | }
161 | break;
162 | case MotionEvent.ACTION_UP:
163 | case MotionEvent.ACTION_POINTER_UP:
164 | mode = FOCUS;
165 | break;
166 | case MotionEvent.ACTION_MOVE:
167 | if (mode == FOCUS) {
168 | } else if (mode == ZOOM) {
169 | float newDist = spacing(event);
170 | if (newDist > 10f) {
171 | float tScale = (newDist - dist) / dist;
172 | if (tScale < 0) {
173 | tScale = tScale * 10;
174 | }
175 | addZoomIn((int) tScale);
176 | }
177 | }
178 | break;
179 | }
180 | return false;
181 | }
182 | });
183 | mSurfaceView.setOnClickListener(new View.OnClickListener() {
184 | @Override
185 | public void onClick(View v) {
186 | try {
187 | pointFocus((int) pointX, (int) pointY);
188 | } catch (Exception e) {
189 | e.printStackTrace();
190 | }
191 | RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(focusIndex.getLayoutParams());
192 | layout.setMargins((int) pointX - 60, (int) pointY - 60, 0, 0);
193 | focusIndex.setLayoutParams(layout);
194 | focusIndex.setVisibility(View.VISIBLE);
195 | ScaleAnimation sa = new ScaleAnimation(3f, 1f, 3f, 1f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
196 | sa.setDuration(800);
197 | focusIndex.startAnimation(sa);
198 |
199 | handler.postDelayed(new Runnable() {
200 | @Override
201 | public void run() {
202 | focusIndex.setVisibility(View.INVISIBLE);
203 | }
204 | }, 700);
205 | }
206 | });
207 | }
208 |
209 | private void addZoomIn(int delta) {
210 | try {
211 | Camera.Parameters params = mCamera.getParameters();
212 | Log.d("Camera", "Is support Zoom " + params.isZoomSupported());
213 | if (!params.isZoomSupported()) {
214 | return;
215 | }
216 | curZoomValue += delta;
217 | if (curZoomValue < 0) {
218 | curZoomValue = 0;
219 | } else if (curZoomValue > params.getMaxZoom()) {
220 | curZoomValue = params.getMaxZoom();
221 | }
222 |
223 | if (!params.isSmoothZoomSupported()) {
224 | params.setZoom(curZoomValue);
225 | mCamera.setParameters(params);
226 | return;
227 | } else {
228 | mCamera.startSmoothZoom(curZoomValue);
229 | }
230 | } catch (Exception e) {
231 | e.printStackTrace();
232 | }
233 | }
234 |
235 | //定点对焦的代码
236 | private void pointFocus(int x, int y) {
237 | mCamera.cancelAutoFocus();
238 | parameters = mCamera.getParameters();
239 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
240 | showPoint(x, y);
241 | }
242 | mCamera.setParameters(parameters);
243 | autoFocus();
244 | }
245 |
246 | /**
247 | * 两点的距离
248 | */
249 | private float spacing(MotionEvent event) {
250 | if (event == null) {
251 | return 0;
252 | }
253 | float x = event.getX(0) - event.getX(1);
254 | float y = event.getY(0) - event.getY(1);
255 | return (float) Math.sqrt(x * x + y * y);
256 | }
257 |
258 | private void showPoint(int x, int y) {
259 | if (parameters.getMaxNumMeteringAreas() > 0) {
260 | List areas = new ArrayList();
261 | //xy变换了
262 | int rectY = -x * 2000 / CameraUtil.screenWidth + 1000;
263 | int rectX = y * 2000 / CameraUtil.screenHeight - 1000;
264 |
265 | int left = rectX < -900 ? -1000 : rectX - 100;
266 | int top = rectY < -900 ? -1000 : rectY - 100;
267 | int right = rectX > 900 ? 1000 : rectX + 100;
268 | int bottom = rectY > 900 ? 1000 : rectY + 100;
269 | Rect area1 = new Rect(left, top, right, bottom);
270 | areas.add(new Camera.Area(area1, 800));
271 | parameters.setMeteringAreas(areas);
272 | }
273 |
274 | parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
275 | }
276 |
277 | //实现自动对焦
278 | private void autoFocus() {
279 | new Thread() {
280 | @Override
281 | public void run() {
282 | try {
283 | sleep(100);
284 | } catch (InterruptedException e) {
285 | e.printStackTrace();
286 | }
287 | if (mCamera == null) {
288 | return;
289 | }
290 | mCamera.autoFocus(new Camera.AutoFocusCallback() {
291 | @Override
292 | public void onAutoFocus(boolean success, Camera camera) {
293 | if (success) {
294 | setupCamera(camera);//实现相机的参数初始化
295 | }
296 | }
297 | });
298 | }
299 | };
300 | }
301 |
302 |
303 | @Override
304 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
305 | mCamera.stopPreview();
306 | startPreview(mCamera, holder);
307 | autoFocus();
308 | }
309 |
310 | @Override
311 | public void surfaceCreated(SurfaceHolder holder) {
312 | startPreview(mCamera, holder);
313 | }
314 |
315 | @Override
316 | public void surfaceDestroyed(SurfaceHolder holder) {
317 | releaseCamera();
318 | }
319 |
320 | public void onResume() {
321 | super.onResume();
322 | if (mCamera == null) {
323 | mCamera = getCamera(cameraPosition);
324 | if (holder != null) {
325 | startPreview(mCamera, holder);
326 | }
327 | }
328 | }
329 |
330 | @Override
331 | public void onPause() {
332 | super.onPause();
333 | releaseCamera();
334 | }
335 |
336 | /**
337 | * 闪光灯开关 开->关->自动
338 | *
339 | * @param mCamera
340 | */
341 | private void turnLight(Camera mCamera) {
342 | if (mCamera == null || mCamera.getParameters() == null
343 | || mCamera.getParameters().getSupportedFlashModes() == null) {
344 | return;
345 | }
346 | Camera.Parameters parameters = mCamera.getParameters();
347 | String flashMode = mCamera.getParameters().getFlashMode();
348 | List supportedModes = mCamera.getParameters().getSupportedFlashModes();
349 | if (Camera.Parameters.FLASH_MODE_OFF.equals(flashMode)
350 | && supportedModes.contains(Camera.Parameters.FLASH_MODE_ON)) {//关闭状态
351 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
352 | mCamera.setParameters(parameters);
353 | openLight.setImageResource(R.drawable.camera_flash_on);
354 | } else if (Camera.Parameters.FLASH_MODE_ON.equals(flashMode)) {//开启状态
355 | if (supportedModes.contains(Camera.Parameters.FLASH_MODE_AUTO)) {
356 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
357 | openLight.setImageResource(R.drawable.camera_flash_auto);
358 | mCamera.setParameters(parameters);
359 | } else if (supportedModes.contains(Camera.Parameters.FLASH_MODE_OFF)) {
360 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
361 | openLight.setImageResource(R.drawable.camera_flash_off);
362 | mCamera.setParameters(parameters);
363 | }
364 | } else if (Camera.Parameters.FLASH_MODE_AUTO.equals(flashMode)
365 | && supportedModes.contains(Camera.Parameters.FLASH_MODE_OFF)) {
366 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
367 | mCamera.setParameters(parameters);
368 | openLight.setImageResource(R.drawable.camera_flash_off);
369 | }
370 | }
371 |
372 | /**
373 | * 获取Camera实例
374 | */
375 | private Camera getCamera(int id) {
376 | Camera camera = null;
377 | try {
378 | camera = Camera.open(id);
379 | } catch (Exception e) {
380 |
381 | }
382 | return camera;
383 | }
384 |
385 | /**
386 | * 预览相机
387 | */
388 | private void startPreview(Camera camera, SurfaceHolder holder) {
389 | try {
390 | setupCamera(camera);
391 | camera.setPreviewDisplay(holder);
392 | //亲测的一个方法 基本覆盖所有手机 将预览矫正
393 | CameraUtil.getInstance().setCameraDisplayOrientation(this, cameraPosition, camera);
394 | camera.startPreview();
395 | } catch (IOException e) {
396 | e.printStackTrace();
397 | }
398 | }
399 |
400 | /**
401 | * 释放相机资源
402 | */
403 | private void releaseCamera() {
404 | if (mCamera != null) {
405 | mCamera.setPreviewCallback(null);
406 | mCamera.stopPreview();
407 | mCamera.release();
408 | mCamera = null;
409 | }
410 | }
411 |
412 | @Override
413 | protected void onDestroy() {
414 | super.onDestroy();
415 | }
416 |
417 | /**
418 | * 设置
419 | */
420 | private void setupCamera(Camera camera) {
421 | Camera.Parameters parameters = camera.getParameters();
422 |
423 | List focusModes = parameters.getSupportedFocusModes();
424 | if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
425 | // Autofocus mode is supported 自动对焦
426 | parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
427 | }
428 |
429 | Camera.Size previewSize = CameraUtil.findBestPreviewResolution(camera);
430 | parameters.setPreviewSize(previewSize.width, previewSize.height);
431 |
432 | Camera.Size pictrueSize = CameraUtil.getInstance().getPropPictureSize(parameters.getSupportedPictureSizes(), 1000);
433 | parameters.setPictureSize(pictrueSize.width, pictrueSize.height);
434 |
435 | camera.setParameters(parameters);
436 |
437 | int picHeight = CameraUtil.screenWidth * previewSize.width / previewSize.height;
438 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(CameraUtil.screenWidth, picHeight);
439 | mSurfaceView.setLayoutParams(params);
440 |
441 | }
442 |
443 | //将bitmap保存在本地,然后通知图库更新
444 | public void saveImageToGallery(Context context, Bitmap bmp) {
445 | // 首先保存图片
446 | File appDir = new File(Environment.getExternalStorageDirectory(), "轻牛");
447 | if (!appDir.exists()) {
448 | appDir.mkdir();
449 | }
450 | String fileName = System.currentTimeMillis() + ".jpg";
451 | File file = new File(appDir, fileName);
452 | try {
453 | FileOutputStream fos = new FileOutputStream(file);
454 | bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);
455 | fos.flush();
456 | fos.close();
457 | } catch (Exception e) {
458 | e.printStackTrace();
459 | Toast.makeText(context, "保存图片失败", Toast.LENGTH_SHORT).show();
460 | }
461 |
462 | // 其次把文件插入到系统图库
463 | try {
464 | MediaStore.Images.Media.insertImage(context.getContentResolver(), file.getAbsolutePath(), fileName, null);
465 | } catch (FileNotFoundException e) {
466 | e.printStackTrace();
467 | Toast.makeText(context, "保存图片失败", Toast.LENGTH_SHORT).show();
468 | }
469 | // 最后通知图库更新
470 | context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + file)));
471 | }
472 |
473 | @Override
474 | public void onClick(View v) {
475 | switch (v.getId()) {
476 | case R.id.back:
477 | finish();
478 | break;
479 |
480 | case R.id.lookPictureIv:
481 | //指定照片
482 | // File appDir = new File(Environment.getExternalStorageDirectory(), "轻牛");
483 | // intent.setDataAndType(Uri.fromFile(appDir), "image/*");
484 |
485 | Intent intent = new Intent();
486 | intent.setAction(Intent.ACTION_VIEW);
487 | intent.setType("image/*");
488 |
489 | startActivity(intent);
490 | break;
491 |
492 | case R.id.takePhoto:
493 | rxPermissions.requestEach(Manifest.permission.WRITE_EXTERNAL_STORAGE).subscribe(new DefaultSubscriber() {
494 | @Override
495 | public void onNext(Permission permission) {
496 | if (permission.granted) {
497 | if (safeToTakePicture) {
498 | safeToTakePicture = false;
499 | mCamera.takePicture(null, null, mJpeg);
500 | }
501 | } else {
502 | AlertDialog.Builder builder = new AlertDialog.Builder(this.context);
503 | builder.setMessage("您未授权读取本地相册权限,将无法打开相册,请在权限管理中开启存储权限")
504 | .setTitle("提示").setPositiveButton("确认", new DialogInterface.OnClickListener() {
505 | @Override
506 | public void onClick(DialogInterface dialog, int which) {
507 | Uri packageURI = Uri.parse("package:" + getPackageName());
508 | Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI);
509 | startActivity(intent);
510 | }
511 | }).setNegativeButton("取消", new DialogInterface.OnClickListener() {
512 | @Override
513 | public void onClick(DialogInterface dialog, int which) {
514 | dialog.dismiss();
515 | }
516 | });
517 | builder.create().show();
518 |
519 | }
520 | }
521 | });
522 |
523 | break;
524 |
525 | case R.id.openLight:
526 | turnLight(mCamera);
527 | break;
528 |
529 | case R.id.cameraSwitch:
530 | releaseCamera();
531 | cameraPosition = (cameraPosition + 1) % mCamera.getNumberOfCameras();
532 | mCamera = getCamera(cameraPosition);
533 | if (holder != null) {
534 | startPreview(mCamera, holder);
535 | }
536 | break;
537 |
538 | }
539 |
540 | }
541 | }
542 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/ysq/customcamera/CameraUtil.java:
--------------------------------------------------------------------------------
1 | package com.example.ysq.customcamera;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Matrix;
7 | import android.hardware.Camera;
8 | import android.hardware.Camera.Size;
9 | import android.util.DisplayMetrics;
10 | import android.util.Log;
11 | import android.view.Surface;
12 |
13 | import java.util.ArrayList;
14 | import java.util.Collections;
15 | import java.util.Comparator;
16 | import java.util.Iterator;
17 | import java.util.List;
18 |
19 | public class CameraUtil {
20 | public static float scale;
21 |
22 | public static int densityDpi;
23 |
24 | public static float fontScale;
25 |
26 | public static int screenWidth;
27 | public static int screenHeight;
28 |
29 | public static void init(Context context) {
30 | DisplayMetrics dm = context.getResources().getDisplayMetrics();
31 | scale = dm.density;
32 | densityDpi = dm.densityDpi;
33 | fontScale = dm.scaledDensity;
34 | if (dm.widthPixels < dm.heightPixels) {
35 | screenWidth = dm.widthPixels;
36 | screenHeight = dm.heightPixels;
37 | } else {
38 | screenWidth = dm.heightPixels;
39 | screenHeight = dm.widthPixels;
40 | }
41 | Log.e("screen", "屏幕宽度是:" + screenWidth + " 高度是:" + screenHeight + " dp:" + scale + " fontScale:" + fontScale);
42 | }
43 |
44 | //降序
45 | private CameraDropSizeComparator dropSizeComparator = new CameraDropSizeComparator();
46 | //升序
47 | private CameraAscendSizeComparator ascendSizeComparator = new CameraAscendSizeComparator();
48 | private static CameraUtil myCamPara = null;
49 |
50 | private CameraUtil() {
51 |
52 | }
53 |
54 | public static CameraUtil getInstance() {
55 | if (myCamPara == null) {
56 | myCamPara = new CameraUtil();
57 | return myCamPara;
58 | } else {
59 | return myCamPara;
60 | }
61 | }
62 |
63 | /**
64 | * 保证预览方向正确
65 | *
66 | * @param activity
67 | * @param cameraId
68 | * @param camera
69 | */
70 | public void setCameraDisplayOrientation(Activity activity,
71 | int cameraId, Camera camera) {
72 | Camera.CameraInfo info =
73 | new Camera.CameraInfo();
74 | Camera.getCameraInfo(cameraId, info);
75 | int rotation = activity.getWindowManager().getDefaultDisplay()
76 | .getRotation();
77 | int degrees = 0;
78 | switch (rotation) {
79 | case Surface.ROTATION_0:
80 | degrees = 0;
81 | break;
82 | case Surface.ROTATION_90:
83 | degrees = 90;
84 | break;
85 | case Surface.ROTATION_180:
86 | degrees = 180;
87 | break;
88 | case Surface.ROTATION_270:
89 | degrees = 270;
90 | break;
91 | }
92 |
93 | int result;
94 | if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
95 | result = (info.orientation + degrees) % 360;
96 | result = (360 - result) % 360; // compensate the mirror
97 | } else { // back-facing
98 | result = (info.orientation - degrees + 360) % 360;
99 | }
100 | camera.setDisplayOrientation(result);
101 | }
102 |
103 |
104 | public Bitmap setTakePicktrueOrientation(int id, Bitmap bitmap) {
105 | Camera.CameraInfo info = new Camera.CameraInfo();
106 | Camera.getCameraInfo(id, info);
107 | bitmap = rotaingImageView(id, info.orientation, bitmap);
108 | return bitmap;
109 | }
110 |
111 | /**
112 | * 把相机拍照返回照片转正
113 | *
114 | * @param angle 旋转角度
115 | * @return bitmap 图片
116 | */
117 | public Bitmap rotaingImageView(int id, int angle, Bitmap bitmap) {
118 | //旋转图片 动作
119 | Matrix matrix = new Matrix();
120 | matrix.postRotate(angle);
121 | //加入翻转 把相机拍照返回照片转正
122 | if (id == 1) {
123 | matrix.postScale(-1, 1);
124 | }
125 | // 创建新的图片
126 | Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
127 | bitmap.getWidth(), bitmap.getHeight(), matrix, true);
128 | return resizedBitmap;
129 | }
130 |
131 | /**
132 | * 获取所有支持的预览尺寸
133 | */
134 | public Size getPropPreviewSize(List list, int minWidth) {
135 | Collections.sort(list, ascendSizeComparator);
136 |
137 | int i = 0;
138 | for (Size s : list) {
139 | if ((s.width >= minWidth)) {
140 | break;
141 | }
142 | i++;
143 | }
144 | if (i == list.size()) {
145 | i = 0;//如果没找到,就选最小的size
146 | }
147 | return list.get(i);
148 | }
149 |
150 | /**
151 | * 获取所有支持的返回图片尺寸
152 | */
153 | public Size getPropPictureSize(List list, int minWidth) {
154 | Collections.sort(list, ascendSizeComparator);
155 |
156 | int i = 0;
157 | for (Size s : list) {
158 | if ((s.width >= minWidth)) {
159 | break;
160 | }
161 | i++;
162 | }
163 | if (i == list.size()) {
164 | i = 0;//如果没找到,就选最小的size
165 | }
166 | return list.get(i);
167 | }
168 |
169 | public boolean equalRate(Size s, float rate) {
170 | float r = (float) (s.width) / (float) (s.height);
171 | if (Math.abs(r - rate) <= 0.03) {
172 | return true;
173 | } else {
174 | return false;
175 | }
176 | }
177 |
178 | //降序
179 | public class CameraDropSizeComparator implements Comparator {
180 | public int compare(Size lhs, Size rhs) {
181 | if (lhs.width == rhs.width) {
182 | return 0;
183 | } else if (lhs.width < rhs.width) {
184 | return 1;
185 | } else {
186 | return -1;
187 | }
188 | }
189 |
190 | }
191 |
192 | //升序
193 | public class CameraAscendSizeComparator implements Comparator {
194 | public int compare(Size lhs, Size rhs) {
195 | if (lhs.width == rhs.width) {
196 | return 0;
197 | } else if (lhs.width > rhs.width) {
198 | return 1;
199 | } else {
200 | return -1;
201 | }
202 | }
203 |
204 | }
205 |
206 | /**
207 | * 打印支持的previewSizes
208 | */
209 | public void printSupportPreviewSize(Camera.Parameters params) {
210 | List previewSizes = params.getSupportedPreviewSizes();
211 | for (int i = 0; i < previewSizes.size(); i++) {
212 | Size size = previewSizes.get(i);
213 | }
214 |
215 | }
216 |
217 | /**
218 | * 打印支持的pictureSizes
219 | */
220 | public void printSupportPictureSize(Camera.Parameters params) {
221 | List pictureSizes = params.getSupportedPictureSizes();
222 | for (int i = 0; i < pictureSizes.size(); i++) {
223 | Size size = pictureSizes.get(i);
224 | }
225 | }
226 |
227 | /**
228 | * 打印支持的聚焦模式
229 | */
230 | public void printSupportFocusMode(Camera.Parameters params) {
231 | List focusModes = params.getSupportedFocusModes();
232 | for (String mode : focusModes) {
233 | }
234 | }
235 |
236 | /**
237 | * 打开闪关灯
238 | */
239 | public void turnLightOn(Camera mCamera) {
240 | if (mCamera == null) {
241 | return;
242 | }
243 | Camera.Parameters parameters = mCamera.getParameters();
244 | if (parameters == null) {
245 | return;
246 | }
247 | List flashModes = parameters.getSupportedFlashModes();
248 | // Check if camera flash exists
249 | if (flashModes == null) {
250 | // Use the screen as a flashlight (next best thing)
251 | return;
252 | }
253 | String flashMode = parameters.getFlashMode();
254 | if (!Camera.Parameters.FLASH_MODE_ON.equals(flashMode)) {
255 | // Turn on the flash
256 | if (flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) {
257 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
258 | mCamera.setParameters(parameters);
259 | } else {
260 | }
261 | }
262 | }
263 |
264 |
265 | /**
266 | * 自动模式闪光灯
267 | */
268 | public void turnLightAuto(Camera mCamera) {
269 | if (mCamera == null) {
270 | return;
271 | }
272 | Camera.Parameters parameters = mCamera.getParameters();
273 | if (parameters == null) {
274 | return;
275 | }
276 | List flashModes = parameters.getSupportedFlashModes();
277 | // Check if camera flash exists
278 | if (flashModes == null) {
279 | // Use the screen as a flashlight (next best thing)
280 | return;
281 | }
282 | String flashMode = parameters.getFlashMode();
283 | if (!Camera.Parameters.FLASH_MODE_AUTO.equals(flashMode)) {
284 | // Turn on the flash
285 | if (flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) {
286 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
287 | mCamera.setParameters(parameters);
288 | } else {
289 | }
290 | }
291 | }
292 |
293 |
294 | /**
295 | * 最小预览界面的分辨率
296 | */
297 | private static final int MIN_PREVIEW_PIXELS = 480 * 320;
298 | /**
299 | * 最大宽高比差
300 | */
301 | private static final double MAX_ASPECT_DISTORTION = 0.15;
302 |
303 |
304 | /**
305 | * 关闭闪光灯
306 | *
307 | * @param mCamera
308 | */
309 | public void turnLightOff(Camera mCamera) {
310 | if (mCamera == null) {
311 | return;
312 | }
313 | Camera.Parameters parameters = mCamera.getParameters();
314 | if (parameters == null) {
315 | return;
316 | }
317 | List flashModes = parameters.getSupportedFlashModes();
318 | String flashMode = parameters.getFlashMode();
319 | // Check if camera flash exists
320 | if (flashModes == null) {
321 | return;
322 | }
323 | if (!Camera.Parameters.FLASH_MODE_OFF.equals(flashMode)) {
324 | // Turn off the flash
325 | if (flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) {
326 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
327 | mCamera.setParameters(parameters);
328 | } else {
329 | }
330 | }
331 | }
332 |
333 | public static Size findBestPreviewResolution(Camera mCamera) {
334 | Camera.Parameters cameraParameters = mCamera.getParameters();
335 | Size defaultPreviewResolution = cameraParameters.getPreviewSize();
336 |
337 | List rawSupportedSizes = cameraParameters.getSupportedPreviewSizes();
338 | if (rawSupportedSizes == null) {
339 | return defaultPreviewResolution;
340 | }
341 |
342 | // 按照分辨率从大到小排序
343 | List supportedPreviewResolutions = new ArrayList(rawSupportedSizes);
344 | Collections.sort(supportedPreviewResolutions, new Comparator() {
345 | @Override
346 | public int compare(Size a, Size b) {
347 | int aPixels = a.height * a.width;
348 | int bPixels = b.height * b.width;
349 | if (bPixels < aPixels) {
350 | return -1;
351 | }
352 | if (bPixels > aPixels) {
353 | return 1;
354 | }
355 | return 0;
356 | }
357 | });
358 |
359 | StringBuilder previewResolutionSb = new StringBuilder();
360 | for (Size supportedPreviewResolution : supportedPreviewResolutions) {
361 | previewResolutionSb.append(supportedPreviewResolution.width).append('x').append(supportedPreviewResolution.height)
362 | .append(' ');
363 | }
364 |
365 | // 移除不符合条件的分辨率
366 | double screenAspectRatio = (double) (screenWidth / screenHeight);
367 | Iterator it = supportedPreviewResolutions.iterator();
368 | while (it.hasNext()) {
369 | Size supportedPreviewResolution = it.next();
370 | int width = supportedPreviewResolution.width;
371 | int height = supportedPreviewResolution.height;
372 |
373 | // 移除低于下限的分辨率,尽可能取高分辨率
374 | if (width * height < MIN_PREVIEW_PIXELS) {
375 | it.remove();
376 | continue;
377 | }
378 |
379 | // 在camera分辨率与屏幕分辨率宽高比不相等的情况下,找出差距最小的一组分辨率
380 | // 由于camera的分辨率是width>height,我们设置的portrait模式中,width height;
383 | int maybeFlippedWidth = isCandidatePortrait ? height : width;
384 | int maybeFlippedHeight = isCandidatePortrait ? width : height;
385 | double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;
386 | double distortion = Math.abs(aspectRatio - screenAspectRatio);
387 |
388 | // 找到与屏幕分辨率完全匹配的预览界面分辨率直接返回
389 | if (maybeFlippedWidth == screenWidth
390 | && maybeFlippedHeight == screenHeight) {
391 | return supportedPreviewResolution;
392 | }
393 |
394 | if (distortion > MAX_ASPECT_DISTORTION) {
395 | it.remove();
396 | continue;
397 | }
398 |
399 | }
400 |
401 | // 如果没有找到合适的,并且还有候选的像素,则设置其中最大比例的,对于配置比较低的机器不太合适
402 | if (!supportedPreviewResolutions.isEmpty()) {
403 | Size largestPreview = supportedPreviewResolutions.get(0);
404 | return largestPreview;
405 | }
406 |
407 | // 没有找到合适的,就返回默认的
408 |
409 | return defaultPreviewResolution;
410 | }
411 | }
412 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/ysq/customcamera/DefaultSubscriber.java:
--------------------------------------------------------------------------------
1 | package com.example.ysq.customcamera;
2 |
3 | import android.content.Context;
4 |
5 | import rx.Subscriber;
6 |
7 | /**
8 | * Created by hdr on 15/9/6.
9 | */
10 | public class DefaultSubscriber extends Subscriber {
11 | Context context;
12 |
13 | public DefaultSubscriber() {
14 | }
15 |
16 | public DefaultSubscriber(Context context) {
17 | this.context = context;
18 | }
19 |
20 | @Override
21 | public void onStart() {
22 |
23 | }
24 |
25 | @Override
26 | public void onCompleted() {
27 |
28 | }
29 |
30 | @Override
31 | public void onError(Throwable e) {
32 | }
33 |
34 | @Override
35 | public void onNext(T t) {
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/ysq/customcamera/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.ysq.customcamera;
2 |
3 | import android.Manifest;
4 | import android.content.DialogInterface;
5 | import android.content.Intent;
6 | import android.net.Uri;
7 | import android.os.Bundle;
8 | import android.provider.Settings;
9 | import android.support.v7.app.AlertDialog;
10 | import android.support.v7.app.AppCompatActivity;
11 | import android.view.View;
12 | import android.widget.Button;
13 |
14 | import com.tbruyelle.rxpermissions.Permission;
15 | import com.tbruyelle.rxpermissions.RxPermissions;
16 |
17 | public class MainActivity extends AppCompatActivity {
18 | RxPermissions rxPermissions;
19 |
20 | @Override
21 | protected void onCreate(Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 | setContentView(R.layout.activity_main);
24 |
25 | rxPermissions = RxPermissions.getInstance(this);
26 |
27 | Button cameraBtn = (Button) findViewById(R.id.cameraBtn);
28 | cameraBtn.setOnClickListener(new View.OnClickListener() {
29 | @Override
30 | public void onClick(View v) {
31 | rxPermissions.requestEach(Manifest.permission.CAMERA).subscribe(new DefaultSubscriber() {
32 | @Override
33 | public void onNext(Permission permission) {
34 | if (permission.granted) {
35 | startActivity(new Intent(MainActivity.this, CameraActivity.class));
36 | } else {
37 | AlertDialog.Builder builder = new AlertDialog.Builder(this.context);
38 | builder.setMessage("您未授权相机权限,将无法拍照,请在权限管理中开启相机权限")
39 | .setTitle("提示").setPositiveButton("确认", new DialogInterface.OnClickListener() {
40 | @Override
41 | public void onClick(DialogInterface dialog, int which) {
42 | Uri packageURI = Uri.parse("package:" + getPackageName());
43 | Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI);
44 | startActivity(intent);
45 | }
46 | }).setNegativeButton("取消", new DialogInterface.OnClickListener() {
47 | @Override
48 | public void onClick(DialogInterface dialog, int which) {
49 | dialog.dismiss();
50 | }
51 | });
52 | builder.create().show();
53 |
54 | }
55 | }
56 | });
57 |
58 | }
59 | });
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/camera_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/drawable-xxhdpi/camera_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/camera_flash_auto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/drawable-xxhdpi/camera_flash_auto.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/camera_flash_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/drawable-xxhdpi/camera_flash_off.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/camera_flash_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/drawable-xxhdpi/camera_flash_on.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/camera_flip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/drawable-xxhdpi/camera_flip.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/camera_library.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/drawable-xxhdpi/camera_library.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/camera_photo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/drawable-xxhdpi/camera_photo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_take_photo.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 | -
13 |
14 |
15 |
16 |
17 | -
18 |
19 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/cam_focus.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_test_camera.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
9 |
10 |
13 |
14 |
19 |
20 |
29 |
30 |
40 |
41 |
42 |
49 |
50 |
59 |
60 |
68 |
69 |
78 |
79 |
80 |
87 |
88 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #FFFFFF
7 | #33B6E7
8 |
9 | #00000000
10 | #000000
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CustomCamera
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/example/ysq/customcamera/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.example.ysq.customcamera;
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.2.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/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/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
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-2.14.1-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 |
--------------------------------------------------------------------------------