supportedFocusModes = params.getSupportedFocusModes();
126 | params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
127 | try {
128 | camera.setParameters(params);
129 | } catch (Exception e) {
130 | Util.e(e);
131 | }
132 | camera.autoFocus(new Camera.AutoFocusCallback() {
133 | @Override
134 | public void onAutoFocus(boolean success, Camera camera) {
135 | //回调后 还原模式
136 | Camera.Parameters params = camera.getParameters();
137 | params.setFocusMode(currentFocusMode);
138 | camera.setParameters(params);
139 | if (success) {
140 | Util.log("focus success");
141 | if (onCameraCaptureListener != null) {
142 | onCameraCaptureListener.onFocusSuccess(x, y);
143 | }
144 | }
145 | }
146 | });
147 |
148 | }
149 |
150 |
151 | /**
152 | * 切换闪光灯状态
153 | *
154 | * 切换闪光灯的时候检查闪光灯是否可用
155 | */
156 | public void enableFlashLight() {
157 | if (!isPreviewing) {
158 | if (onCameraCaptureListener != null) {
159 | onCameraCaptureListener.onError(new Exception("预览的时候才能操作闪光灯"));
160 | }
161 | return;
162 | }
163 | // 判断是否正在录像
164 | if (isRecording) {
165 | if (onCameraCaptureListener != null) {
166 | onCameraCaptureListener.onError(new Exception("正在录像,无法操作"));
167 | }
168 | return;
169 | }
170 |
171 | // 再切换闪光灯
172 | if (currentFlashMode.equals(Camera.Parameters.FLASH_MODE_OFF)) {
173 | currentFlashMode = Camera.Parameters.FLASH_MODE_ON;
174 | } else if (currentFlashMode.equals(Camera.Parameters.FLASH_MODE_ON)) {
175 | currentFlashMode = Camera.Parameters.FLASH_MODE_TORCH;
176 | } else if (currentFlashMode.equals(Camera.Parameters.FLASH_MODE_TORCH)) {
177 | currentFlashMode = Camera.Parameters.FLASH_MODE_OFF;
178 | }
179 | Camera.Parameters parameters = camera.getParameters();
180 | parameters.setFlashMode(currentFlashMode);
181 | camera.setParameters(parameters);
182 | if (onCameraCaptureListener != null) {
183 | onCameraCaptureListener.onToggleSplash(currentFlashMode);
184 | }
185 | }
186 |
187 |
188 | /**
189 | * 切换镜头
190 | */
191 | public void switchCamera() {
192 |
193 | int cameraNum = Camera.getNumberOfCameras();
194 | if (cameraNum < 2) {
195 | if (onCameraCaptureListener != null) {
196 | onCameraCaptureListener.onError(new Exception("您的手机不支持前置拍摄"));
197 | }
198 | return;
199 | }
200 | if (!isPreviewing) {
201 | if (onCameraCaptureListener != null) {
202 | onCameraCaptureListener.onError(new Exception("非预览状态无法切换摄像头"));
203 | }
204 | return;
205 | }
206 |
207 | if (isRecording) {
208 | if (onCameraCaptureListener != null) {
209 | onCameraCaptureListener.onError(new Exception("正在录像,无法切换摄像头"));
210 | }
211 | return;
212 | }
213 | if (cameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
214 | cameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
215 | } else {
216 | cameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
217 | }
218 | // 重新预览
219 | startPreview();
220 | }
221 |
222 | /**
223 | * 拍照
224 | */
225 | public void capturePhoto(final int orientation) {
226 | if (!isPreviewing) {
227 | if (onCameraCaptureListener != null) {
228 | onCameraCaptureListener.onError(new Exception("非预览状态,无法拍照"));
229 | }
230 | return;
231 | }
232 | camera.takePicture(null, null, new Camera.PictureCallback() {
233 | @Override
234 | public void onPictureTaken(byte[] data, Camera camera) {
235 | try {
236 | // int orientation = ((TakePhotoVideoActivity) mActivity).getOrientation();
237 | // 将图片保存在 DIRECTORY_DCIM 内存卡中
238 | Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
239 | Matrix matrix = new Matrix();
240 | if (cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT) {
241 | matrix.setRotate(-90 - orientation);
242 | matrix.postScale(-1, 1);
243 | } else {
244 | matrix.setRotate(90 + orientation);
245 | }
246 | bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
247 | // 创建文件
248 | String parentPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath() + File.separator + "Camera";
249 | File mediaStorageDir = new File(parentPath);
250 | if (!mediaStorageDir.exists()) {
251 | mediaStorageDir.mkdirs();
252 | }
253 | File mediaFile = new File(mediaStorageDir.getPath() + File.separator + Util.randomName() + ".jpg");
254 | FileOutputStream stream = new FileOutputStream(mediaFile);
255 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
256 | stream.flush();
257 | stream.close();
258 | // 回调
259 | if (onCameraCaptureListener != null) {
260 | onCameraCaptureListener.onCapturePhoto(mediaFile.getAbsolutePath());
261 | }
262 | } catch (IOException e) {
263 | if (onCameraCaptureListener != null) {
264 | onCameraCaptureListener.onError(e);
265 | }
266 | }
267 | }
268 | });
269 | }
270 |
271 |
272 | /**
273 | * 开始录制
274 | */
275 | public void captureRecordStart(int orientation) {
276 | // 生成视频文件
277 | String parentPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath()
278 | + File.separator + "Camera";
279 | File parentFile = new File(parentPath);
280 | if (!parentFile.exists()) {
281 | parentFile.mkdirs();
282 | }
283 | fileVideo = parentPath + File.separator + Util.randomName() + ".mp4";
284 | // File file = new File(fileVideo);
285 | // if (!file.exists()) {
286 | // try {
287 | // file.createNewFile();
288 | // } catch (IOException e) {
289 | // e.printStackTrace();
290 | // }
291 | // }
292 | captureRecordEnd();
293 | camera.stopPreview();
294 | camera.unlock();
295 | mediaRecorder = new MediaRecorder();
296 | mediaRecorder.setCamera(camera);
297 | mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
298 | mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
299 | if (cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT) {
300 | // 前置
301 | mediaRecorder.setOrientationHint(270 - orientation);
302 | } else {
303 | mediaRecorder.setOrientationHint((90 + orientation) % 360);
304 | }
305 |
306 | // 自定义的设置mediaeecorder 这里设置视频质量最低 录制出来的视频体积很小 对质量不是要求不高的可以使用
307 | try {
308 | mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
309 | mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
310 | mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
311 | //设置分辨率,应设置在格式和编码器设置之后
312 | mediaRecorder.setVideoSize(previewInfo.getVideoWidth(), previewInfo.getVideoHeight());
313 | // mediaRecorder.setVideoEncodingBitRate(52 * defaultVideoFrameRate * 1024);
314 | // mediaRecorder.setVideoEncodingBitRate(1400 * 1024);
315 | mediaRecorder.setVideoEncodingBitRate(3000 * 1024);
316 | mediaRecorder.setAudioEncodingBitRate(65536);
317 | mediaRecorder.setAudioSamplingRate(44100);
318 | } catch (Exception e) {
319 | Util.e(e);
320 | // 如果出错,则使用
321 | mediaRecorder.setProfile(Util.getBestCamcorderProfile(cameraId));
322 | }
323 |
324 |
325 | mediaRecorder.setVideoFrameRate(previewInfo.getVideoRate());
326 | // 设置最大录制时间
327 | mediaRecorder.setMaxFileSize(30 * 1024 * 1024);
328 | mediaRecorder.setMaxDuration(10 * 60 * 60 * 1000);
329 | // mediaRecorder.setPreviewDisplay(surfaceView.getSurfaceTexture().);
330 | mediaRecorder.setOutputFile(fileVideo);
331 |
332 | // 一切就绪
333 | try {
334 | mediaRecorder.prepare();
335 | } catch (IOException e) {
336 | e.printStackTrace();
337 | }
338 | mediaRecorder.start();
339 | isRecording = true;
340 | }
341 |
342 |
343 | /**
344 | * 录制完成
345 | */
346 | public void captureRecordEnd() {
347 | if (!isRecording) {
348 | return;
349 | }
350 | if (mediaRecorder == null) {
351 | return;
352 | }
353 | try {
354 | mediaRecorder.stop();
355 | mediaRecorder.release();
356 | mediaRecorder = null;
357 | isRecording = false;
358 | if (onCameraCaptureListener != null) {
359 | onCameraCaptureListener.onCaptureRecord(fileVideo);
360 | }
361 | } catch (Exception e) {
362 | Util.e(e);
363 | isRecording = false;
364 | // 删除已经创建的视频文件
365 | File file = new File(fileVideo);
366 | if (file.exists()) {
367 | file.delete();
368 | }
369 | }
370 | }
371 |
372 | /**
373 | * 录制视频失败
374 | */
375 | public void captureRecordFailed() {
376 | if (!isRecording) {
377 | return;
378 | }
379 | if (mediaRecorder == null) {
380 | return;
381 | }
382 | try {
383 | mediaRecorder.stop();
384 | mediaRecorder.release();
385 | mediaRecorder = null;
386 | } catch (Exception e) {
387 | Util.e(e);
388 | }
389 | isRecording = false;
390 | // 删除已经创建的视频文件
391 | File file = new File(fileVideo);
392 | if (file.exists()) {
393 | file.delete();
394 | }
395 | }
396 |
397 | /**
398 | * 销毁一切
399 | */
400 | public void destroy() {
401 | if (camera != null) {
402 | if (isPreviewing) {
403 | camera.stopPreview();
404 | isPreviewing = false;
405 | camera.setPreviewCallback(null);
406 | camera.setPreviewCallbackWithBuffer(null);
407 | }
408 | camera.release();
409 | camera = null;
410 | }
411 | }
412 |
413 |
414 | // —————————————————————————————————私有方法—————————————————————————————————————————
415 |
416 | /**
417 | * 设置camera 的 Parameters
418 | */
419 | private void setCameraParameter() {
420 | Camera.Parameters parameters = camera.getParameters();
421 | // 设置预览的尺寸
422 | parameters.setPreviewSize(previewInfo.getPreviewWidth(), previewInfo.getPreviewHeight());
423 | parameters.setPictureSize(previewInfo.getPictureWidth(), previewInfo.getPictureHeight());
424 | parameters.setJpegQuality(100);
425 | // 获取支持的对焦模式
426 | List supportedFocus = parameters.getSupportedFocusModes();
427 | if (supportedFocus != null && supportedFocus.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
428 | parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
429 | }
430 |
431 | // 设置闪光灯模式之前检查该模式是否可用
432 | List flashModes = parameters.getSupportedFlashModes();
433 | if (flashModes == null) {
434 | flashModes = new ArrayList<>();
435 | }
436 | if (flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) {
437 | // 设置闪光灯模式
438 | parameters.setFlashMode(currentFlashMode);
439 | if (onCameraCaptureListener != null) {
440 | onCameraCaptureListener.onToggleSplash(currentFlashMode);
441 | }
442 | } else {
443 | // 该设备不支持闪光灯
444 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
445 | if (onCameraCaptureListener != null) {
446 | onCameraCaptureListener.onToggleSplash(null);
447 | }
448 | }
449 |
450 | camera.setParameters(parameters);
451 | }
452 |
453 |
454 | /**
455 | * Convert touch position x:y to {@link Camera.Area} position -1000:-1000 to 1000:1000.
456 | */
457 | private Rect calculateTapArea(float x, float y) {
458 | float focusAreaSize = 300;
459 | int areaSize = Float.valueOf(focusAreaSize * 1.0f).intValue();
460 | int centerY = 0;
461 | int centerX = 0;
462 | centerY = (int) (x / surfaceView.getMeasuredWidth() * 2000 - 1000);
463 | centerX = (int) (y / surfaceView.getMeasuredHeight() * 2000 - 1000);
464 | int left = clamp(centerX - areaSize / 2, -1000, 1000);
465 | int top = clamp(centerY - areaSize / 2, -1000, 1000);
466 | RectF rectF = new RectF(left, top, left + areaSize, top + areaSize);
467 | return new Rect(Math.round(rectF.left), Math.round(rectF.top), Math.round(rectF.right), Math.round(rectF.bottom));
468 | }
469 |
470 | /**
471 | * @param x
472 | * @param min
473 | * @param max
474 | * @return
475 | */
476 | private int clamp(int x, int min, int max) {
477 | if (x > max) {
478 | return max;
479 | }
480 | if (x < min) {
481 | return min;
482 | }
483 | return x;
484 | }
485 |
486 |
487 | /**
488 | * surface callback
489 | */
490 | private SurfaceHolder.Callback surfaceCallBack = new SurfaceHolder.Callback() {
491 | @Override
492 | public void surfaceCreated(SurfaceHolder holder) {
493 | Util.log("surfaceCallBack>>>>>>surfaceCreated");
494 | }
495 |
496 | @Override
497 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
498 | Util.log("surfaceCallBack>>>>>>surfaceChanged");
499 | if (holder.getSurface() == null) {
500 | return;
501 | }
502 | // 开始预览
503 | startPreview();
504 | }
505 |
506 | @Override
507 | public void surfaceDestroyed(SurfaceHolder holder) {
508 | Util.log("surfaceCallBack>>>>>>surfaceDestroyed");
509 | destroy();
510 | }
511 | };
512 |
513 |
514 | private TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
515 | @Override
516 | public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
517 | Util.log("textureListener>>>>>>onSurfaceTextureAvailable");
518 | if (surface == null) {
519 | return;
520 | }
521 | // 开始预览
522 | startPreview();
523 | }
524 |
525 | @Override
526 | public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
527 | Util.log("textureListener>>>>>>onSurfaceTextureSizeChanged");
528 | }
529 |
530 | @Override
531 | public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
532 | Util.log("textureListener>>>>>>onSurfaceTextureDestroyed");
533 | destroy();
534 | return false;
535 | }
536 |
537 | @Override
538 | public void onSurfaceTextureUpdated(SurfaceTexture surface) {
539 |
540 | }
541 | };
542 | }
543 |
--------------------------------------------------------------------------------
/camera/src/main/java/com/hyfun/camera/p2v/OnCameraCaptureListener.java:
--------------------------------------------------------------------------------
1 | package com.hyfun.camera.p2v;
2 |
3 | /**
4 | * Created by HyFun on 2019/11/22.
5 | * Email: 775183940@qq.com
6 | * Description:
7 | */
8 | interface OnCameraCaptureListener {
9 |
10 | void onToggleSplash(String flashMode);
11 |
12 | void onFocusSuccess(float x, float y);
13 |
14 | void onCapturePhoto(String photoPath);
15 |
16 | void onCaptureRecord(String filePath);
17 |
18 | void onError(Throwable throwable);
19 | }
20 |
--------------------------------------------------------------------------------
/camera/src/main/java/com/hyfun/camera/p2v/PreviewInfo.java:
--------------------------------------------------------------------------------
1 | package com.hyfun.camera.p2v;
2 |
3 | import android.content.Context;
4 | import android.hardware.Camera;
5 | import android.view.WindowManager;
6 |
7 | import java.util.ArrayList;
8 | import java.util.Collections;
9 | import java.util.Comparator;
10 | import java.util.List;
11 |
12 | /**
13 | * Created by HyFun on 2019/11/22.
14 | * Email: 775183940@qq.com
15 | * Description:
16 | */
17 | public class PreviewInfo {
18 | private int previewWidth; // 预览宽度
19 | private int previewHeight; // 预览高度
20 |
21 | private int pictureWidth; // 拍照宽度
22 | private int pictureHeight; // 拍照高度
23 |
24 | private int videoWidth; // 拍摄视频宽度
25 | private int videoHeight; // 拍摄视频高度
26 |
27 | private int videoRate; // 视频帧率
28 |
29 | private int screenWidth;
30 | private int screenHeight;
31 |
32 |
33 | private Context context;
34 | private Camera camera;
35 |
36 | public PreviewInfo(Context context, Camera camera) {
37 | this.context = context;
38 | this.camera = camera;
39 |
40 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
41 | screenWidth = wm.getDefaultDisplay().getWidth();
42 | screenHeight = wm.getDefaultDisplay().getHeight();
43 | }
44 |
45 |
46 | /**
47 | * 计算
48 | */
49 | public void notifyDataChanged() {
50 | Util.log("===============================================");
51 | boolean hasSupportRate = false;
52 | List supportedPreviewFrameRates = getSupportedPreviewFrameRates(camera);
53 | Util.log("supportRate::" + supportedPreviewFrameRates.toString());
54 | if (supportedPreviewFrameRates != null
55 | && supportedPreviewFrameRates.size() > 0) {
56 | for (int i = 0; i < supportedPreviewFrameRates.size(); i++) {
57 | int supportRate = supportedPreviewFrameRates.get(i);
58 | if (supportRate == 30) {
59 | videoRate = 30;
60 | hasSupportRate = true;
61 | break;
62 | }
63 | }
64 | if (!hasSupportRate) {
65 | for (int i = 0; i < supportedPreviewFrameRates.size(); i++) {
66 | int supportRate = supportedPreviewFrameRates.get(i);
67 | if (supportRate <= 30) {
68 | videoRate = supportRate;
69 | hasSupportRate = true;
70 | break;
71 | }
72 | }
73 | }
74 |
75 | if (!hasSupportRate) {
76 | videoRate = supportedPreviewFrameRates.get(supportedPreviewFrameRates.size() - 1);
77 | hasSupportRate = true;
78 | }
79 | }
80 |
81 |
82 | // 设置预览时的宽高
83 | // 取一个最相近屏幕尺寸的预览宽高
84 | {
85 | List resolutionList = getSupportedPreviewSizes(camera);
86 | if (resolutionList != null && resolutionList.size() > 0) {
87 | Camera.Size previewSize = null;
88 | boolean hasSize = false;
89 | // 手机支持的分辨率 列表
90 | Util.log("--------support preview list-----------");
91 | for (int i = 0; i < resolutionList.size(); i++) {
92 | Camera.Size size = resolutionList.get(i);
93 | Util.log("width:" + size.width + " height:" + size.height);
94 | }
95 |
96 | // 找一个比例相近的进行比较
97 | if (!hasSize) {
98 | List distanceList = new ArrayList<>();
99 | for (int i = 0; i < resolutionList.size(); i++) {
100 | Camera.Size size = resolutionList.get(i);
101 | Util.log("width:" + size.width + " height:" + size.height);
102 | double scale = 1.0f * size.height / size.width;
103 | double scaleScreen = 1.0 * screenWidth / screenHeight;
104 | distanceList.add(Math.abs(scale - scaleScreen));
105 | }
106 | // 找到最小值
107 | int position = distanceList.indexOf(Collections.min(distanceList));
108 | // 找到了
109 | previewSize = resolutionList.get(position);
110 | previewWidth = previewSize.width;
111 | previewHeight = previewSize.height;
112 | hasSize = previewWidth >= 720;
113 | }
114 |
115 | if (!hasSize)
116 | for (int i = 0; i < resolutionList.size(); i++) {
117 | Camera.Size size = resolutionList.get(i);
118 | if (size != null && size.width == 1920 && size.height == 1080) {
119 | previewSize = size;
120 | previewWidth = previewSize.width;
121 | previewHeight = previewSize.height;
122 | hasSize = true;
123 | break;
124 | }
125 | }
126 |
127 | if (!hasSize)
128 | for (int i = 0; i < resolutionList.size(); i++) {
129 | Camera.Size size = resolutionList.get(i);
130 | if (size != null && size.width == screenHeight && size.height == screenWidth) {
131 | previewSize = size;
132 | previewWidth = previewSize.width;
133 | previewHeight = previewSize.height;
134 | hasSize = true;
135 | break;
136 | }
137 | }
138 |
139 | if (!hasSize)
140 | for (int i = 0; i < resolutionList.size(); i++) {
141 | Camera.Size size = resolutionList.get(i);
142 | if (size != null && size.height == screenWidth) {
143 | previewSize = size;
144 | previewWidth = previewSize.width;
145 | previewHeight = previewSize.height;
146 | hasSize = true;
147 | break;
148 | }
149 | }
150 |
151 | //如果相机不支持上述分辨率,使用中分辨率
152 | if (!hasSize) {
153 | int mediumResolution = resolutionList.size() / 2;
154 | if (mediumResolution >= resolutionList.size())
155 | mediumResolution = resolutionList.size() - 1;
156 | previewSize = resolutionList.get(mediumResolution);
157 | previewWidth = previewSize.width;
158 | previewHeight = previewSize.height;
159 | }
160 | }
161 | }
162 |
163 | // 设置拍照照片的宽高
164 | {
165 | List pictureSizeList = getSupportedPictureSizes(camera);
166 | if (pictureSizeList != null && !pictureSizeList.isEmpty()) {
167 | Camera.Size pictureSize = null;
168 | boolean hasSize = false;
169 | // 手机支持的分辨率 列表
170 | Util.log("---------support picture list----------");
171 | for (int i = 0; i < pictureSizeList.size(); i++) {
172 | Camera.Size size = pictureSizeList.get(i);
173 | Util.log("width:" + size.width + " height:" + size.height);
174 | }
175 |
176 | if (!hasSize)
177 | for (int i = 0; i < pictureSizeList.size(); i++) {
178 | Camera.Size size = pictureSizeList.get(i);
179 | if (size != null && size.width == 1920 && size.height == 1080) {
180 | pictureSize = size;
181 | pictureWidth = pictureSize.width;
182 | pictureHeight = pictureSize.height;
183 | hasSize = true;
184 | break;
185 | }
186 | }
187 |
188 | if (!hasSize)
189 | for (int i = 0; i < pictureSizeList.size(); i++) {
190 | Camera.Size size = pictureSizeList.get(i);
191 | float scale = (float) size.height / (float) size.width;
192 | if (size != null && scale == 0.5625f) {
193 | pictureSize = size;
194 | pictureWidth = pictureSize.width;
195 | pictureHeight = pictureSize.height;
196 | hasSize = true;
197 | break;
198 | }
199 | }
200 |
201 | if (!hasSize)
202 | for (int i = 0; i < pictureSizeList.size(); i++) {
203 | Camera.Size size = pictureSizeList.get(i);
204 | if (size != null && size.width == screenHeight && size.height == screenWidth) {
205 | pictureSize = size;
206 | pictureWidth = pictureSize.width;
207 | pictureHeight = pictureSize.height;
208 | hasSize = true;
209 | break;
210 | }
211 | }
212 |
213 | if (!hasSize)
214 | for (int i = 0; i < pictureSizeList.size(); i++) {
215 | Camera.Size size = pictureSizeList.get(i);
216 | if (size != null && size.height == screenWidth) {
217 | pictureSize = size;
218 | pictureWidth = pictureSize.width;
219 | pictureHeight = pictureSize.height;
220 | hasSize = true;
221 | break;
222 | }
223 | }
224 |
225 | //如果相机不支持上述分辨率,使用中分辨率
226 | if (!hasSize) {
227 | int mediumResolution = pictureSizeList.size() / 2;
228 | if (mediumResolution >= pictureSizeList.size())
229 | mediumResolution = pictureSizeList.size() - 1;
230 | pictureSize = pictureSizeList.get(mediumResolution);
231 | pictureWidth = pictureSize.width;
232 | pictureHeight = pictureSize.height;
233 | }
234 | }
235 | }
236 | // 设置拍摄视频时的宽高
237 | {
238 | List videoSizeList = getSupportedVideoSizes(camera);
239 | if (videoSizeList != null && !videoSizeList.isEmpty()) {
240 | Camera.Size videoSize = null;
241 | boolean hasSize = false;
242 | Util.log("---------support video list----------");
243 | for (int i = 0; i < videoSizeList.size(); i++) {
244 | Camera.Size size = videoSizeList.get(i);
245 | Util.log("width:" + size.width + " height:" + size.height + " scale:" + ((float) size.height / (float) size.width));
246 | }
247 |
248 | if (!hasSize)
249 | for (int i = 0; i < videoSizeList.size(); i++) {
250 | Camera.Size size = videoSizeList.get(i);
251 | float scale = (float) size.height / (float) size.width;
252 | if (size != null && size.width >= 960 && scale == 0.5625f) {
253 | videoSize = size;
254 | videoWidth = videoSize.width;
255 | videoHeight = videoSize.height;
256 | hasSize = true;
257 | break;
258 | }
259 | }
260 |
261 | if (!hasSize)
262 | for (int i = 0; i < videoSizeList.size(); i++) {
263 | Camera.Size size = videoSizeList.get(i);
264 | if (size != null && size.width == 1280 && size.height == 720) {
265 | videoSize = size;
266 | videoWidth = videoSize.width;
267 | videoHeight = videoSize.height;
268 | hasSize = true;
269 | break;
270 | }
271 | }
272 |
273 | if (!hasSize)
274 | for (int i = 0; i < videoSizeList.size(); i++) {
275 | Camera.Size size = videoSizeList.get(i);
276 | if (size != null && size.width == screenHeight && size.height == screenWidth) {
277 | videoSize = size;
278 | videoWidth = videoSize.width;
279 | videoHeight = videoSize.height;
280 | hasSize = true;
281 | break;
282 | }
283 | }
284 |
285 | if (!hasSize)
286 | for (int i = 0; i < videoSizeList.size(); i++) {
287 | Camera.Size size = videoSizeList.get(i);
288 | if (size != null && size.height == screenWidth) {
289 | videoSize = size;
290 | videoWidth = videoSize.width;
291 | videoHeight = videoSize.height;
292 | hasSize = true;
293 | break;
294 | }
295 | }
296 |
297 | if (!hasSize)
298 | for (int i = 0; i < videoSizeList.size(); i++) {
299 | Camera.Size size = videoSizeList.get(i);
300 | float scale = (float) size.height / (float) size.width;
301 | if (size != null && scale == 0.5625f) {
302 | videoSize = size;
303 | videoWidth = videoSize.width;
304 | videoHeight = videoSize.height;
305 | hasSize = true;
306 | break;
307 | }
308 | }
309 |
310 | //如果相机不支持上述分辨率,使用中分辨率
311 | if (!hasSize) {
312 | int mediumResolution = videoSizeList.size() / 2;
313 | if (mediumResolution >= videoSizeList.size())
314 | mediumResolution = videoSizeList.size() - 1;
315 | videoSize = videoSizeList.get(mediumResolution);
316 | videoWidth = videoSize.width;
317 | videoHeight = videoSize.height;
318 | }
319 | }
320 | }
321 |
322 | Util.log("screen wh:" + screenWidth + "," + screenHeight + " preview wh:" + previewWidth + "," + previewHeight + " picture wh:" + pictureWidth + "," + pictureHeight + " video wh:" + videoWidth + "," + videoHeight + " videoRate:" + videoRate);
323 | Util.log("===============================================");
324 | }
325 |
326 |
327 | public int getPreviewWidth() {
328 | return previewWidth;
329 | }
330 |
331 | public int getPreviewHeight() {
332 | return previewHeight;
333 | }
334 |
335 | public int getPictureWidth() {
336 | return pictureWidth;
337 | }
338 |
339 | public int getPictureHeight() {
340 | return pictureHeight;
341 | }
342 |
343 | public int getVideoWidth() {
344 | return videoWidth;
345 | }
346 |
347 | public int getVideoHeight() {
348 | return videoHeight;
349 | }
350 |
351 | public int getVideoRate() {
352 | return videoRate;
353 | }
354 |
355 |
356 | // —————————————————————————————————————————————————私有方法———————————————————————————————————————————————————————————
357 |
358 | /**
359 | * 获取camera支持的预览尺寸集合
360 | *
361 | * @param camera
362 | * @return
363 | */
364 | private List getSupportedPreviewFrameRates(Camera camera) {
365 | List supportedPreviewFrameRates = camera.getParameters().getSupportedPreviewFrameRates();
366 | Collections.sort(supportedPreviewFrameRates, new Comparator() {
367 | @Override
368 | public int compare(Integer integer, Integer t1) {
369 | return t1 - integer;
370 | }
371 | });
372 | return supportedPreviewFrameRates;
373 | }
374 |
375 |
376 | /**
377 | * 获取手机摄像头支持预览的尺寸集合
378 | *
379 | * @param camera
380 | * @return
381 | */
382 | private List getSupportedPreviewSizes(Camera camera) {
383 | Camera.Parameters parameters = camera.getParameters();
384 | List previewSizes = parameters.getSupportedPreviewSizes();
385 | Collections.sort(previewSizes, new Comparator() {
386 | @Override
387 | public int compare(Camera.Size lhs, Camera.Size rhs) {
388 | if (lhs.height != rhs.height) {
389 | return rhs.height - lhs.height;
390 | } else {
391 | return rhs.width - lhs.width;
392 | }
393 | }
394 | });
395 | return previewSizes;
396 | }
397 |
398 | /**
399 | * 获取手机摄像头支持拍摄照片像素的集合
400 | *
401 | * @param camera
402 | * @return
403 | */
404 | private List getSupportedPictureSizes(Camera camera) {
405 | Camera.Parameters parameters = camera.getParameters();
406 | List previewSizes = parameters.getSupportedPictureSizes();
407 | Collections.sort(previewSizes, new Comparator() {
408 | @Override
409 | public int compare(Camera.Size lhs, Camera.Size rhs) {
410 | if (lhs.height != rhs.height)
411 | return rhs.height - lhs.height;
412 | else
413 | return rhs.width - lhs.width;
414 | }
415 | });
416 | return previewSizes;
417 | }
418 |
419 |
420 | /**
421 | * 获取摄像头支持拍摄视频的像素集合
422 | *
423 | * @param camera
424 | * @return
425 | */
426 | private List getSupportedVideoSizes(Camera camera) {
427 | Camera.Parameters parameters = camera.getParameters();
428 | List previewSizes = parameters.getSupportedVideoSizes();
429 | Collections.sort(previewSizes, new Comparator() {
430 | @Override
431 | public int compare(Camera.Size lhs, Camera.Size rhs) {
432 | if (lhs.height != rhs.height)
433 | return lhs.height - rhs.height;
434 | else
435 | return lhs.width - rhs.width;
436 | }
437 | });
438 | return previewSizes;
439 | }
440 | }
441 |
--------------------------------------------------------------------------------
/camera/src/main/java/com/hyfun/camera/p2v/Util.java:
--------------------------------------------------------------------------------
1 | package com.hyfun.camera.p2v;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.res.Resources;
7 | import android.graphics.Color;
8 | import android.graphics.Point;
9 | import android.media.CamcorderProfile;
10 | import android.net.Uri;
11 | import android.os.Build;
12 | import android.util.Log;
13 | import android.view.Display;
14 | import android.view.KeyCharacterMap;
15 | import android.view.KeyEvent;
16 | import android.view.View;
17 | import android.view.ViewConfiguration;
18 | import android.view.Window;
19 | import android.view.WindowManager;
20 | import android.view.animation.AlphaAnimation;
21 | import android.view.animation.Animation;
22 | import android.view.animation.AnimationSet;
23 | import android.view.animation.ScaleAnimation;
24 |
25 | import java.io.File;
26 | import java.text.SimpleDateFormat;
27 | import java.util.Date;
28 |
29 | class Util {
30 |
31 | private static final String TAG = "FunCamera::";
32 |
33 | public static final void log(String message) {
34 | Log.d(TAG, message);
35 | }
36 |
37 | public static final void e(Throwable e) {
38 | Log.e(TAG, e.getMessage(), e);
39 | }
40 |
41 |
42 | interface Const {
43 | int 类型_照片 = 0;
44 | int 类型_视频 = 1;
45 | }
46 |
47 |
48 | /**
49 | * 设置内容全屏,即内容延伸至状态栏底部,状态栏文字还在
50 | *
51 | * @param activity
52 | */
53 | public static void setFullScreen(Activity activity) {
54 |
55 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
56 | Window window = activity.getWindow();
57 |
58 | // 适配刘海屏幕
59 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
60 | WindowManager.LayoutParams lp = window.getAttributes();
61 | lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
62 | window.setAttributes(lp);
63 | }
64 |
65 | int uiFlags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
66 | uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
67 | //Activity全屏显示,但导航栏不会被隐藏覆盖,导航栏依然可见,Activity底部布局部分会被导航栏遮住。
68 | uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
69 |
70 | // 隐藏状态栏
71 | uiFlags |= View.INVISIBLE;
72 | uiFlags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
73 |
74 |
75 | window.getDecorView().setSystemUiVisibility(uiFlags);
76 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
77 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
78 | window.setStatusBarColor(Color.TRANSPARENT);
79 | window.setNavigationBarColor(Color.parseColor("#60000000"));
80 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
81 | // 设置透明状态栏,这样才能让 ContentView 向上
82 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
83 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
84 | }
85 | }
86 |
87 | /**
88 | * 生成文件名称
89 | *
90 | * @return
91 | */
92 | public static String randomName() {
93 | SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
94 | return dateFormat.format(new Date());
95 | }
96 |
97 | /**
98 | * 通知系统相册更新了
99 | */
100 | public static final void notifyAlbumDataChanged(Context context, File file) {
101 | //通知相册更新
102 | Uri uri = Uri.fromFile(file);
103 | // 通知图库更新
104 | Intent scannerIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri);
105 | context.sendBroadcast(scannerIntent);
106 | }
107 |
108 |
109 | /**
110 | * 解决录像时清晰度问题
111 | *
112 | * 视频清晰度顺序 High 1080 720 480 cif qvga gcif 详情请查看 CamcorderProfile.java
113 | * 在12秒mp4格式视频大小维持在1M左右时,以下四个选择效果最佳
114 | *
115 | * 不同的CamcorderProfile.QUALITY_ 代表每帧画面的清晰度,
116 | * 变换 profile.videoBitRate 可减少每秒钟帧数
117 | *
118 | * @param cameraID 前摄 Camera.CameraInfo.CAMERA_FACING_FRONT /后摄 Camera.CameraInfo.CAMERA_FACING_BACK
119 | * @return
120 | */
121 | public static CamcorderProfile getBestCamcorderProfile(int cameraID) {
122 | CamcorderProfile profile = CamcorderProfile.get(cameraID, CamcorderProfile.QUALITY_LOW);
123 | if (CamcorderProfile.hasProfile(cameraID, CamcorderProfile.QUALITY_720P)) {
124 | //对比上面480 这个选择 动作大时马赛克!!
125 | profile = CamcorderProfile.get(cameraID, CamcorderProfile.QUALITY_720P);
126 | profile.videoBitRate = profile.videoBitRate / 10;
127 | return profile;
128 | }
129 | if (CamcorderProfile.hasProfile(cameraID, CamcorderProfile.QUALITY_480P)) {
130 | //对比下面720 这个选择 每帧不是很清晰
131 | profile = CamcorderProfile.get(cameraID, CamcorderProfile.QUALITY_480P);
132 | profile.videoBitRate = profile.videoBitRate / 2;
133 | return profile;
134 | }
135 | if (CamcorderProfile.hasProfile(cameraID, CamcorderProfile.QUALITY_CIF)) {
136 | profile = CamcorderProfile.get(cameraID, CamcorderProfile.QUALITY_CIF);
137 | return profile;
138 | }
139 | if (CamcorderProfile.hasProfile(cameraID, CamcorderProfile.QUALITY_QVGA)) {
140 | profile = CamcorderProfile.get(cameraID, CamcorderProfile.QUALITY_QVGA);
141 | return profile;
142 | }
143 | return profile;
144 | }
145 |
146 |
147 | /**
148 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
149 | */
150 | public static int dip2px(Context context, float dpValue) {
151 | final float scale = context.getResources().getDisplayMetrics().density;
152 | return (int) (dpValue * scale + 0.5f);
153 | }
154 |
155 |
156 | /**
157 | * 判断导航栏是否显示
158 | *
159 | * @return
160 | */
161 | public static boolean isNavigationBarShow(Activity activity) {
162 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
163 | Display display = activity.getWindowManager().getDefaultDisplay();
164 | Point size = new Point();
165 | Point realSize = new Point();
166 | display.getSize(size);
167 | display.getRealSize(realSize);
168 | return realSize.y != size.y;
169 | } else {
170 | boolean menu = ViewConfiguration.get(activity).hasPermanentMenuKey();
171 | boolean back = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
172 | if (menu || back) {
173 | return false;
174 | } else {
175 | return true;
176 | }
177 | }
178 | }
179 |
180 | /**
181 | * 获取导航栏高度
182 | *
183 | * @param activity
184 | * @return
185 | */
186 | public static int getNavigationBarHeight(Activity activity) {
187 | if (!isNavigationBarShow(activity)) {
188 | return 0;
189 | }
190 | Resources resources = activity.getResources();
191 | int resourceId = resources.getIdentifier("navigation_bar_height",
192 | "dimen", "android");
193 | //获取NavigationBar的高度
194 | int height = resources.getDimensionPixelSize(resourceId);
195 | return height;
196 | }
197 |
198 |
199 | public static int getSceenHeight(Activity activity) {
200 | return activity.getWindowManager().getDefaultDisplay().getHeight() + getNavigationBarHeight(activity);
201 | }
202 |
203 |
204 | /**
205 | * focus view的缩放动画
206 | */
207 | public static void scale(final View view) {
208 | view.clearAnimation();
209 | view.setVisibility(View.VISIBLE);
210 |
211 | AnimationSet set = new AnimationSet(false);
212 |
213 |
214 | ScaleAnimation scale = new ScaleAnimation(1.6f, 1.0f, 1.6f, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
215 | scale.setDuration(400);
216 | set.addAnimation(scale);
217 |
218 | AlphaAnimation alpha = new AlphaAnimation(0f, 1.0f);
219 | alpha.setDuration(400);
220 | set.addAnimation(alpha);
221 |
222 |
223 | view.startAnimation(set);
224 | set.setAnimationListener(new Animation.AnimationListener() {
225 | @Override
226 | public void onAnimationStart(Animation animation) {
227 |
228 | }
229 |
230 | @Override
231 | public void onAnimationEnd(Animation animation) {
232 | view.setVisibility(View.GONE);
233 | }
234 |
235 | @Override
236 | public void onAnimationRepeat(Animation animation) {
237 |
238 | }
239 | });
240 |
241 |
242 | }
243 |
244 |
245 | }
246 |
--------------------------------------------------------------------------------
/camera/src/main/java/com/hyfun/camera/widget/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.hyfun.camera.widget;
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 static final String TAG = AutoFitTextureView.class.getSimpleName();
29 |
30 |
31 | private int mRatioWidth = 0;
32 | private int mRatioHeight = 0;
33 |
34 | public AutoFitTextureView(Context context) {
35 | this(context, null);
36 | }
37 |
38 | public AutoFitTextureView(Context context, AttributeSet attrs) {
39 | this(context, attrs, 0);
40 | }
41 |
42 | public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {
43 | super(context, attrs, defStyle);
44 | }
45 |
46 | /**
47 | * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
48 | * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
49 | * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
50 | *
51 | * @param width Relative horizontal size
52 | * @param height Relative vertical size
53 | */
54 | public void setAspectRatio(int width, int height) {
55 | if (width < 0 || height < 0) {
56 | throw new IllegalArgumentException("Size cannot be negative.");
57 | }
58 | mRatioWidth = width;
59 | mRatioHeight = height;
60 | requestLayout();
61 | }
62 |
63 |
64 | @Override
65 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
66 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
67 | int width = MeasureSpec.getSize(widthMeasureSpec);
68 | int height = MeasureSpec.getSize(heightMeasureSpec);
69 | if (0 == mRatioWidth || 0 == mRatioHeight) {
70 | setMeasuredDimension(width, height);
71 | } else {
72 | if (width > height * mRatioWidth / mRatioHeight) {
73 | setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
74 | } else {
75 | setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
76 | }
77 | }
78 | }
79 | }
--------------------------------------------------------------------------------
/camera/src/main/java/com/hyfun/camera/widget/CaptureButton.java:
--------------------------------------------------------------------------------
1 | package com.hyfun.camera.widget;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Paint;
8 | import android.graphics.RectF;
9 | import android.os.Handler;
10 | import android.os.Message;
11 | import android.support.annotation.Nullable;
12 | import android.support.v4.view.GestureDetectorCompat;
13 | import android.util.AttributeSet;
14 | import android.view.MotionEvent;
15 | import android.view.View;
16 | import android.view.ViewConfiguration;
17 |
18 | import com.hyfun.camera.R;
19 |
20 | /**
21 | * Created by CKZ on 2017/8/9.
22 | */
23 |
24 | public class CaptureButton extends View {
25 | private static final int RING_WHAT = 101;
26 | private static final int MSG_RECORD_START = 102;
27 | private static final int MSG_RECORD_END = 103;
28 |
29 |
30 | private float circleWidth;//外圆环宽度
31 | private int outCircleColor;//外圆颜色
32 | private int innerCircleColor;//内圆颜色
33 | private int progressColor;//进度条颜色
34 |
35 | private Paint outRoundPaint = new Paint(); //外圆画笔
36 | private Paint mCPaint = new Paint();//进度画笔
37 | private Paint innerRoundPaint = new Paint();
38 | private float width; //自定义view的宽度
39 | private float height; //自定义view的高度
40 | private float outRaduis; //外圆半径
41 | private float innerRaduis;//内圆半径
42 | private GestureDetectorCompat mDetector;//手势识别
43 | private boolean isLongClick = false;//是否长按
44 | private float startAngle = -90;//开始角度
45 | private float progress;// 进度
46 |
47 | private boolean isRecording = false;
48 |
49 |
50 | private long lastActionDownTime = 0; // 记录点击录制视频时的时间
51 | private long lastActionUpTime = 0; // 记录最后一次手指抬起的时间
52 |
53 |
54 | public CaptureButton(Context context) {
55 | this(context, null);
56 | }
57 |
58 | public CaptureButton(Context context, @Nullable AttributeSet attrs) {
59 | this(context, attrs, 0);
60 |
61 | }
62 |
63 | public CaptureButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
64 | super(context, attrs, defStyleAttr);
65 | init(context, attrs);
66 | }
67 |
68 | private void init(Context context, AttributeSet attrs) {
69 | TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CaptureButton);
70 | outCircleColor = array.getColor(R.styleable.CaptureButton_outCircleColor, Color.parseColor("#E0E0E0"));
71 | innerCircleColor = array.getColor(R.styleable.CaptureButton_innerCircleColor, Color.WHITE);
72 | progressColor = array.getColor(R.styleable.CaptureButton_progressColor, Color.GREEN);
73 | mLoadingTime = array.getInteger(R.styleable.CaptureButton_maxSeconds, 15000);
74 | }
75 |
76 | private void resetParams() {
77 | width = getWidth();
78 | height = getHeight();
79 | circleWidth = width * 0.13f;
80 | outRaduis = (float) (Math.min(width, height) / 2.4);
81 | innerRaduis = outRaduis - circleWidth;
82 | }
83 |
84 |
85 | @Override
86 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
87 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
88 | int width = MeasureSpec.getSize(widthMeasureSpec);
89 | int height = MeasureSpec.getSize(heightMeasureSpec);
90 | if (width > height) {
91 | setMeasuredDimension(height, height);
92 | } else {
93 | setMeasuredDimension(width, width);
94 | }
95 | }
96 |
97 | @Override
98 | protected void onDraw(Canvas canvas) {
99 | resetParams();
100 | //画外圆
101 | outRoundPaint.setAntiAlias(true);
102 | outRoundPaint.setColor(outCircleColor);
103 | if (isLongClick) {
104 | outRaduis = (float) (Math.min(width, height) / 2.0f);
105 | } else {
106 | }
107 | canvas.drawCircle(width / 2, height / 2, outRaduis, outRoundPaint);
108 | //画内圆
109 | innerRoundPaint.setAntiAlias(true);
110 | innerRoundPaint.setColor(innerCircleColor);
111 | if (isLongClick) {
112 | // 内圆缩小为原来的一半
113 | canvas.drawCircle(width / 2, height / 2, innerRaduis / 2.0f, innerRoundPaint);
114 | //画外原环
115 | mCPaint.setAntiAlias(true);
116 | mCPaint.setColor(progressColor);
117 | mCPaint.setStyle(Paint.Style.STROKE);
118 | int ringWidth = 12;
119 | mCPaint.setStrokeWidth(ringWidth);
120 | RectF rectF = new RectF(ringWidth / 2.0f, ringWidth / 2.0f, width - ringWidth / 2.0f, height - ringWidth / 2.0f);
121 | canvas.drawArc(rectF, startAngle, 360 * (1.0f * progress / mLoadingTime), false, mCPaint);
122 | } else {
123 | canvas.drawCircle(width / 2, height / 2, innerRaduis, innerRoundPaint);
124 | }
125 |
126 | }
127 |
128 | private Runnable longPressRunnable = new Runnable() {
129 | @Override
130 | public void run() {
131 | handler.sendEmptyMessage(MSG_RECORD_START);
132 | }
133 | };
134 |
135 | @Override
136 | public boolean onTouchEvent(MotionEvent event) {
137 | switch (event.getAction()) {
138 | case MotionEvent.ACTION_DOWN:
139 | if (mode != Mode.MODE_CAPTURE) {
140 | postDelayed(longPressRunnable, ViewConfiguration.getLongPressTimeout());
141 | }
142 | break;
143 | case MotionEvent.ACTION_UP:
144 | case MotionEvent.ACTION_CANCEL:
145 | removeCallbacks(longPressRunnable);
146 | long now = System.currentTimeMillis();
147 | // 先判断是否是点击
148 | if (!isLongClick && !isRecording && mode != Mode.MODE_RECORD) {
149 | if (Math.abs(now - lastActionUpTime) > 1000) {
150 | if (listener != null) {
151 | listener.onCapture();
152 | }
153 | } else {
154 | if (listener != null) {
155 | listener.onCaptureError("您的操作太快了");
156 | }
157 | }
158 | }
159 |
160 | if (isLongClick && mode != Mode.MODE_CAPTURE) {
161 | if (Math.abs(now - lastActionDownTime) > 1000) {
162 | if (listener != null) {
163 | listener.onCaptureRecordEnd();
164 | }
165 | } else {
166 | // 录制时间太短
167 | if (listener != null) {
168 | listener.onCaptureError("录制时间太短");
169 | }
170 | }
171 | handler.sendEmptyMessage(MSG_RECORD_END);
172 | }
173 | isRecording = false;
174 | lastActionUpTime = now;
175 | break;
176 | }
177 | return true;
178 | }
179 |
180 |
181 | private Handler handler = new Handler() {
182 | @Override
183 | public void handleMessage(Message msg) {
184 | super.handleMessage(msg);
185 | if (msg.what == RING_WHAT) {
186 | if (!isLongClick) {
187 | return;
188 | }
189 | if (progress < mLoadingTime) {
190 | progress = System.currentTimeMillis() - lastActionDownTime;
191 | postInvalidate();
192 | handler.sendEmptyMessageDelayed(RING_WHAT, 100);
193 | } else {
194 | // 时间到了
195 | if (listener != null) {
196 | listener.onCaptureRecordEnd();
197 | }
198 | handler.sendEmptyMessage(MSG_RECORD_END);
199 | }
200 | } else if (msg.what == MSG_RECORD_START) {
201 | // 开始录制
202 | lastActionDownTime = System.currentTimeMillis();
203 | isRecording = true;
204 | if (Math.abs(lastActionUpTime - lastActionDownTime) <= 1000) {
205 | if (listener != null) {
206 | listener.onCaptureError("您的操作太快了");
207 | }
208 | } else {
209 | isLongClick = true;
210 | if (listener != null) {
211 | listener.onCaptureRecordStart();
212 | }
213 | handler.sendEmptyMessage(RING_WHAT);
214 | }
215 | } else if (msg.what == MSG_RECORD_END) {
216 | isLongClick = false;
217 | progress = 0;
218 | postInvalidate();
219 | }
220 | }
221 | };
222 | // ——————————————————————————————私有方法——————————————————————————————
223 |
224 | // ——————————————————————————————SET方法——————————————————————————————
225 | /**
226 | * 拍摄时长
227 | */
228 | private long mLoadingTime;
229 |
230 | public void setDuration(long duration) {
231 | mLoadingTime = duration;
232 | }
233 |
234 | /**
235 | * 拍摄模式
236 | */
237 | private int mode;
238 |
239 | public void setMode(int mode) {
240 | this.mode = mode;
241 | }
242 |
243 | /**
244 | * 操作监听
245 | */
246 | private OnProgressTouchListener listener;
247 |
248 | public void setOnProgressTouchListener(OnProgressTouchListener listener) {
249 | this.listener = listener;
250 | }
251 |
252 |
253 | /**
254 | * 进度触摸监听
255 | */
256 | public interface OnProgressTouchListener {
257 | // 拍照
258 | void onCapture();
259 |
260 | // 开始录像
261 | void onCaptureRecordStart();
262 |
263 | // 停止录像
264 | void onCaptureRecordEnd();
265 |
266 | // 拍摄异常
267 | void onCaptureError(String message);
268 | }
269 |
270 | /**
271 | * 拍摄模式
272 | */
273 | public interface Mode {
274 | // 拍照
275 | int MODE_CAPTURE = 1;
276 |
277 | // 录像
278 | int MODE_RECORD = 2;
279 |
280 | // 拍照+录像
281 | int MODE_CAPTURE_RECORD = 3;
282 | }
283 |
284 | }
--------------------------------------------------------------------------------
/camera/src/main/java/com/hyfun/camera/widget/FunWaveView.java:
--------------------------------------------------------------------------------
1 | package com.hyfun.camera.widget;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Paint;
8 | import android.support.annotation.Nullable;
9 | import android.util.AttributeSet;
10 | import android.view.View;
11 |
12 | import com.hyfun.camera.R;
13 |
14 | import java.util.ArrayList;
15 |
16 | /**
17 | * author: rivenlee
18 | * date: 2018/10/30
19 | * email: rivenlee0@gmail.com
20 | */
21 | public class FunWaveView extends View {
22 | private ArrayList datas = new ArrayList<>();
23 | private short max = 300;
24 | private float mWidth;
25 | private float mHeight;
26 | private float space = 1f;
27 | private Paint mWavePaint;
28 | private Paint baseLinePaint;
29 | private int mWaveColor = Color.BLACK;
30 | private int mBaseLineColor = Color.BLACK;
31 | private float waveStrokeWidth = 4f;
32 | private int invalidateTime = 1000 / 100;
33 | private long drawTime;
34 | private boolean isMaxConstant = false;
35 |
36 | public FunWaveView(Context context) {
37 | this(context, null);
38 | }
39 |
40 | public FunWaveView(Context context, @Nullable AttributeSet attrs) {
41 | this(context, attrs, 0);
42 | }
43 |
44 | public FunWaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
45 | super(context, attrs, defStyleAttr);
46 | init(attrs, defStyleAttr);
47 | }
48 |
49 | private void init(AttributeSet attrs, int defStyle) {
50 | final TypedArray a = getContext().obtainStyledAttributes(
51 | attrs, R.styleable.FunWaveView, defStyle, 0);
52 | mWaveColor = a.getColor(
53 | R.styleable.FunWaveView_waveColor,
54 | mWaveColor);
55 | mBaseLineColor = a.getColor(
56 | R.styleable.FunWaveView_baselineColor,
57 | mBaseLineColor);
58 |
59 | waveStrokeWidth = a.getDimension(
60 | R.styleable.FunWaveView_waveStokeWidth,
61 | waveStrokeWidth);
62 |
63 | max = (short) a.getInt(R.styleable.FunWaveView_maxValue, max);
64 | invalidateTime = a.getInt(R.styleable.FunWaveView_invalidateTime, invalidateTime);
65 |
66 | space = a.getDimension(R.styleable.FunWaveView_space, space);
67 | a.recycle();
68 | initPainters();
69 |
70 | }
71 |
72 | private void initPainters() {
73 | mWavePaint = new Paint();
74 | mWavePaint.setColor(mWaveColor);// 画笔为color
75 | mWavePaint.setStrokeWidth(waveStrokeWidth);// 设置画笔粗细
76 | mWavePaint.setAntiAlias(true);
77 | mWavePaint.setFilterBitmap(true);
78 | mWavePaint.setStrokeCap(Paint.Cap.ROUND);
79 | mWavePaint.setStyle(Paint.Style.FILL);
80 |
81 | baseLinePaint = new Paint();
82 | baseLinePaint.setColor(mBaseLineColor);// 画笔为color
83 | baseLinePaint.setStrokeWidth(1f);// 设置画笔粗细
84 | baseLinePaint.setAntiAlias(true);
85 | baseLinePaint.setFilterBitmap(true);
86 | baseLinePaint.setStyle(Paint.Style.FILL);
87 | }
88 |
89 | public short getMax() {
90 | return max;
91 | }
92 |
93 | public void setMax(short max) {
94 | this.max = max;
95 | }
96 |
97 | public float getSpace() {
98 | return space;
99 | }
100 |
101 | public void setSpace(float space) {
102 | this.space = space;
103 | }
104 |
105 | public int getmWaveColor() {
106 | return mWaveColor;
107 | }
108 |
109 | public void setmWaveColor(int mWaveColor) {
110 | this.mWaveColor = mWaveColor;
111 | invalidateNow();
112 | }
113 |
114 | public int getmBaseLineColor() {
115 | return mBaseLineColor;
116 | }
117 |
118 | public void setmBaseLineColor(int mBaseLineColor) {
119 | this.mBaseLineColor = mBaseLineColor;
120 | invalidateNow();
121 | }
122 |
123 | public float getWaveStrokeWidth() {
124 | return waveStrokeWidth;
125 | }
126 |
127 | public void setWaveStrokeWidth(float waveStrokeWidth) {
128 | this.waveStrokeWidth = waveStrokeWidth;
129 | invalidateNow();
130 | }
131 |
132 | public int getInvalidateTime() {
133 | return invalidateTime;
134 | }
135 |
136 | public void setInvalidateTime(int invalidateTime) {
137 | this.invalidateTime = invalidateTime;
138 | }
139 |
140 | public boolean isMaxConstant() {
141 | return isMaxConstant;
142 | }
143 |
144 | public void setMaxConstant(boolean maxConstant) {
145 | isMaxConstant = maxConstant;
146 | }
147 |
148 | /**
149 | * 如果改变相应配置 需要刷新相应的paint设置
150 | */
151 | public void invalidateNow() {
152 | initPainters();
153 | invalidate();
154 | }
155 |
156 | public void addData(short data) {
157 |
158 | if (data < 0) {
159 | data = (short) -data;
160 | }
161 | if (data > max && !isMaxConstant) {
162 | max = data;
163 | }
164 | if (datas.size() > mWidth / space) {
165 | synchronized (this) {
166 | datas.remove(0);
167 | datas.add(data);
168 | }
169 | } else {
170 | datas.add(data);
171 | }
172 | if (System.currentTimeMillis() - drawTime > invalidateTime) {
173 | invalidate();
174 | drawTime = System.currentTimeMillis();
175 | }
176 |
177 | }
178 |
179 | public void clear() {
180 | datas.clear();
181 | invalidateNow();
182 | }
183 |
184 |
185 | @Override
186 | protected void onDraw(Canvas canvas) {
187 | canvas.translate(0, mHeight / 2);
188 | drawBaseLine(canvas);
189 | drawWave(canvas);
190 | }
191 |
192 | @Override
193 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
194 | mWidth = w;
195 | mHeight = h;
196 | }
197 |
198 | private void drawWave(Canvas mCanvas) {
199 | for (int i = 0; i < datas.size(); i++) {
200 | float x = (i) * space;
201 | float y = (float) datas.get(i) / max * mHeight / 2;
202 | mCanvas.drawLine(x, -y, x, y, mWavePaint);
203 | }
204 |
205 | }
206 |
207 | private void drawBaseLine(Canvas mCanvas) {
208 | mCanvas.drawLine(0, 0, mWidth, 0, baseLinePaint);
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/camera/src/main/res/anim/fun_camera_activity_down_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/camera/src/main/res/anim/fun_camera_activity_down_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
13 |
--------------------------------------------------------------------------------
/camera/src/main/res/anim/fun_camera_activity_up_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
13 |
14 |
--------------------------------------------------------------------------------
/camera/src/main/res/anim/fun_camera_activity_up_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/camera/src/main/res/drawable/camera_ic_camera_flash_auto_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/camera/src/main/res/drawable/camera_ic_capture_flash_off_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/camera/src/main/res/drawable/camera_ic_capture_flash_on_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/camera/src/main/res/drawable/camera_ic_capture_switch_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/camera/src/main/res/drawable/camera_ic_keyboard_arrow_down_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/camera/src/main/res/drawable/camera_ic_preview_back_24dp.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/camera/src/main/res/drawable/camera_shape_background_preview_confirm.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/camera/src/main/res/drawable/camera_shape_background_preview_outline.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/camera/src/main/res/drawable/fun_camera_layer_audio_record_seekbar_style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
13 |
14 |
15 |
16 | -
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/camera/src/main/res/drawable/fun_camera_shape_audio_record_seekbar_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/camera/src/main/res/drawable/fun_camera_shape_background_circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/camera/src/main/res/drawable/fun_camera_shape_background_circle_outline.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/camera/src/main/res/drawable/func_camera_ic_audio_record_play_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/camera/src/main/res/drawable/func_camera_ic_audio_record_stop_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/camera/src/main/res/layout/activity_camera_capture.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/camera/src/main/res/layout/camera_fragment_capture_preview.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
19 |
20 |
24 |
25 |
28 |
29 |
35 |
36 |
43 |
44 |
48 |
49 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/camera/src/main/res/layout/camera_fragment_capture_record.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
21 |
22 |
26 |
27 |
30 |
31 |
36 |
37 |
44 |
45 |
49 |
50 |
57 |
58 |
59 |
60 |
61 |
66 |
67 |
74 |
75 |
81 |
82 |
86 |
87 |
94 |
95 |
96 |
100 |
101 |
110 |
111 |
112 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/camera/src/main/res/layout/fun_camera_audio_record_dialog_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
14 |
15 |
19 |
20 |
29 |
30 |
37 |
38 |
48 |
49 |
59 |
60 |
61 |
72 |
73 |
74 |
75 |
76 |
77 |
82 |
83 |
88 |
89 |
95 |
96 |
103 |
104 |
117 |
118 |
126 |
127 |
128 |
132 |
133 |
144 |
145 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/camera/src/main/res/mipmap-hdpi/fun_camera_img_capture_focus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yofun/android-lib-camera/c2432a22f6b5d70cffb86fa9332091e5e179ec92/camera/src/main/res/mipmap-hdpi/fun_camera_img_capture_focus.png
--------------------------------------------------------------------------------
/camera/src/main/res/values/color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #09BE5D
5 |
6 |
7 |
8 |
9 | #ffffff
10 | #737373
11 |
--------------------------------------------------------------------------------
/camera/src/main/res/values/fun_camera_attr.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 |
--------------------------------------------------------------------------------
/camera/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 | 24dp
8 |
9 |
10 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
15 |
16 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yofun/android-lib-camera/c2432a22f6b5d70cffb86fa9332091e5e179ec92/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Sep 29 13:09:13 CST 2019
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-5.4.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/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 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
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 Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/screenshot/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yofun/android-lib-camera/c2432a22f6b5d70cffb86fa9332091e5e179ec92/screenshot/demo.gif
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':camera'
2 | rootProject.name='Android-Library-Camera'
3 |
--------------------------------------------------------------------------------