capacitor-community-multilens-camerapreview 5.0.1 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +16 -16
  2. package/android/build.gradle +57 -55
  3. package/android/src/main/AndroidManifest.xml +4 -4
  4. package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java +1005 -1008
  5. package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +543 -544
  6. package/android/src/main/java/com/ahm/capacitor/camera/preview/CustomSurfaceView.java +23 -23
  7. package/android/src/main/java/com/ahm/capacitor/camera/preview/CustomTextureView.java +29 -29
  8. package/android/src/main/java/com/ahm/capacitor/camera/preview/Preview.java +386 -386
  9. package/android/src/main/java/com/ahm/capacitor/camera/preview/TapGestureDetector.java +24 -24
  10. package/android/src/main/res/layout/bridge_layout_main.xml +15 -15
  11. package/android/src/main/res/layout/camera_activity.xml +68 -68
  12. package/android/src/main/res/values/camera_ids.xml +4 -4
  13. package/android/src/main/res/values/camera_theme.xml +9 -9
  14. package/android/src/main/res/values/colors.xml +3 -3
  15. package/android/src/main/res/values/strings.xml +3 -3
  16. package/android/src/main/res/values/styles.xml +3 -3
  17. package/dist/esm/definitions.d.ts +82 -80
  18. package/dist/esm/definitions.js +1 -1
  19. package/dist/esm/definitions.js.map +1 -1
  20. package/dist/esm/index.d.ts +4 -4
  21. package/dist/esm/index.js +6 -6
  22. package/dist/esm/index.js.map +1 -1
  23. package/dist/esm/web.d.ts +30 -28
  24. package/dist/esm/web.js +146 -155
  25. package/dist/esm/web.js.map +1 -1
  26. package/dist/plugin.cjs.js +146 -150
  27. package/dist/plugin.cjs.js.map +1 -1
  28. package/dist/plugin.js +147 -151
  29. package/dist/plugin.js.map +1 -1
  30. package/ios/Plugin/CameraController.swift +732 -733
  31. package/ios/Plugin/Info.plist +24 -24
  32. package/ios/Plugin/Plugin.h +10 -10
  33. package/ios/Plugin/Plugin.m +18 -18
  34. package/ios/Plugin/Plugin.swift +309 -308
  35. package/package.json +85 -78
  36. package/CapacitorCommunityMultilensCamerapreview.podspec +0 -17
  37. package/dist/docs.json +0 -408
@@ -1,1008 +1,1005 @@
1
- package com.ahm.capacitor.camera.preview;
2
-
3
- import android.app.Activity;
4
- import android.app.Fragment;
5
- import android.content.Context;
6
- import android.content.pm.PackageManager;
7
- import android.content.res.Configuration;
8
- import android.graphics.Bitmap;
9
- import android.graphics.Bitmap.CompressFormat;
10
- import android.graphics.BitmapFactory;
11
- import android.graphics.Canvas;
12
- import android.graphics.ImageFormat;
13
- import android.graphics.Matrix;
14
- import android.graphics.Rect;
15
- import android.graphics.YuvImage;
16
- import android.hardware.Camera;
17
- import android.hardware.Camera.PictureCallback;
18
- import android.hardware.Camera.ShutterCallback;
19
- import android.hardware.camera2.CameraManager;
20
- import android.media.AudioManager;
21
- import android.media.CamcorderProfile;
22
- import android.media.MediaRecorder;
23
- import android.os.Bundle;
24
- import android.util.Base64;
25
- import android.util.DisplayMetrics;
26
- import android.util.Log;
27
- import android.view.GestureDetector;
28
- import android.view.Gravity;
29
- import android.view.LayoutInflater;
30
- import android.view.MotionEvent;
31
- import android.view.Surface;
32
- import android.view.Surface;
33
- import android.view.SurfaceHolder;
34
- import android.view.SurfaceView;
35
- import android.view.View;
36
- import android.view.ViewGroup;
37
- import android.view.ViewTreeObserver;
38
- import android.widget.FrameLayout;
39
- import android.widget.RelativeLayout;
40
- import androidx.exifinterface.media.ExifInterface;
41
- import java.io.ByteArrayInputStream;
42
- import java.io.ByteArrayOutputStream;
43
- import java.io.File;
44
- import java.io.FileOutputStream;
45
- import java.io.IOException;
46
- import java.util.Arrays;
47
- import java.util.List;
48
- import java.util.UUID;
49
-
50
- public class CameraActivity extends Fragment {
51
-
52
- public interface CameraPreviewListener {
53
- void onPictureTaken(String originalPicture);
54
- void onPictureTakenError(String message);
55
- void onSnapshotTaken(String originalPicture);
56
- void onSnapshotTakenError(String message);
57
- void onFocusSet(int pointX, int pointY);
58
- void onFocusSetError(String message);
59
- void onBackButton();
60
- void onCameraStarted();
61
- void onStartRecordVideo();
62
- void onStartRecordVideoError(String message);
63
- void onStopRecordVideo(String file);
64
- void onStopRecordVideoError(String error);
65
- }
66
-
67
- private CameraPreviewListener eventListener;
68
- private static final String TAG = "CameraActivity";
69
- public FrameLayout mainLayout;
70
- public FrameLayout frameContainerLayout;
71
-
72
- private Preview mPreview;
73
- private boolean canTakePicture = true;
74
-
75
- private View view;
76
- private Camera.Parameters cameraParameters;
77
- private Camera mCamera;
78
- private int numberOfCameras;
79
- private int cameraCurrentlyLocked;
80
- private int currentQuality;
81
-
82
- private enum RecordingState {
83
- INITIALIZING,
84
- STARTED,
85
- STOPPED
86
- }
87
-
88
- private RecordingState mRecordingState = RecordingState.INITIALIZING;
89
- private MediaRecorder mRecorder = null;
90
- private String recordFilePath;
91
- private float opacity;
92
-
93
- // The first rear facing camera
94
- private int defaultCameraId;
95
- public String defaultCamera;
96
- public boolean tapToTakePicture;
97
- public boolean dragEnabled;
98
- public boolean tapToFocus;
99
- public boolean disableExifHeaderStripping;
100
- public boolean storeToFile;
101
- public boolean toBack;
102
- public boolean enableOpacity = false;
103
- public boolean enableZoom = false;
104
-
105
- public int width;
106
- public int height;
107
- public int x;
108
- public int y;
109
-
110
- public void setEventListener(CameraPreviewListener listener) {
111
- eventListener = listener;
112
- }
113
-
114
- private String appResourcesPackage;
115
-
116
- @Override
117
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
118
- appResourcesPackage = getActivity().getPackageName();
119
-
120
- // Inflate the layout for this fragment
121
- view = inflater.inflate(getResources().getIdentifier("camera_activity", "layout", appResourcesPackage), container, false);
122
- createCameraPreview();
123
- return view;
124
- }
125
-
126
- public void setRect(int x, int y, int width, int height) {
127
- this.x = x;
128
- this.y = y;
129
- this.width = width;
130
- this.height = height;
131
- }
132
-
133
- private void createCameraPreview() {
134
- if (mPreview == null) {
135
- setDefaultCameraId();
136
-
137
- //set box position and size
138
- FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(width, height);
139
- layoutParams.setMargins(x, y, 0, 0);
140
- frameContainerLayout =
141
- (FrameLayout) view.findViewById(getResources().getIdentifier("frame_container", "id", appResourcesPackage));
142
- frameContainerLayout.setLayoutParams(layoutParams);
143
-
144
- //video view
145
- mPreview = new Preview(getActivity(), enableOpacity);
146
- mainLayout = (FrameLayout) view.findViewById(getResources().getIdentifier("video_view", "id", appResourcesPackage));
147
- mainLayout.setLayoutParams(
148
- new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
149
- );
150
- mainLayout.addView(mPreview);
151
- mainLayout.setEnabled(false);
152
-
153
- if (enableZoom) {
154
- this.setupTouchAndBackButton();
155
- }
156
- }
157
- }
158
-
159
-
160
- private void setupTouchAndBackButton() {
161
- final GestureDetector gestureDetector = new GestureDetector(getActivity().getApplicationContext(), new TapGestureDetector());
162
-
163
- getActivity()
164
- .runOnUiThread(
165
- new Runnable() {
166
- @Override
167
- public void run() {
168
- frameContainerLayout.setClickable(true);
169
- frameContainerLayout.setOnTouchListener(
170
- new View.OnTouchListener() {
171
- private int mLastTouchX;
172
- private int mLastTouchY;
173
- private int mPosX = 0;
174
- private int mPosY = 0;
175
-
176
- @Override
177
- public boolean onTouch(View v, MotionEvent event) {
178
- FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) frameContainerLayout.getLayoutParams();
179
-
180
- boolean isSingleTapTouch = gestureDetector.onTouchEvent(event);
181
- int action = event.getAction();
182
- int eventCount = event.getPointerCount();
183
- Log.d(TAG, "onTouch event, action, count: " + event + ", " + action + ", " + eventCount);
184
- if (eventCount > 1) {
185
- // handle multi-touch events
186
- Camera.Parameters params = mCamera.getParameters();
187
- if (action == MotionEvent.ACTION_POINTER_DOWN) {
188
- mDist = getFingerSpacing(event);
189
- } else if (action == MotionEvent.ACTION_MOVE && params.isZoomSupported()) {
190
- handleZoom(event, params);
191
- }
192
- } else {
193
- if (action != MotionEvent.ACTION_MOVE && isSingleTapTouch) {
194
- if (tapToTakePicture && tapToFocus) {
195
- setFocusArea(
196
- (int) event.getX(0),
197
- (int) event.getY(0),
198
- new Camera.AutoFocusCallback() {
199
- public void onAutoFocus(boolean success, Camera camera) {
200
- if (success) {
201
- takePicture(0, 0, 85);
202
- } else {
203
- Log.d(TAG, "onTouch:" + " setFocusArea() did not suceed");
204
- }
205
- }
206
- }
207
- );
208
- } else if (tapToTakePicture) {
209
- takePicture(0, 0, 85);
210
- } else if (tapToFocus) {
211
- setFocusArea(
212
- (int) event.getX(0),
213
- (int) event.getY(0),
214
- new Camera.AutoFocusCallback() {
215
- public void onAutoFocus(boolean success, Camera camera) {
216
- if (success) {
217
- // A callback to JS might make sense here.
218
- } else {
219
- Log.d(TAG, "onTouch:" + " setFocusArea() did not suceed");
220
- }
221
- }
222
- }
223
- );
224
- }
225
- return true;
226
- } else {
227
- if (dragEnabled) {
228
- int x;
229
- int y;
230
-
231
- switch (event.getAction()) {
232
- case MotionEvent.ACTION_DOWN:
233
- if (mLastTouchX == 0 || mLastTouchY == 0) {
234
- mLastTouchX = (int) event.getRawX() - layoutParams.leftMargin;
235
- mLastTouchY = (int) event.getRawY() - layoutParams.topMargin;
236
- } else {
237
- mLastTouchX = (int) event.getRawX();
238
- mLastTouchY = (int) event.getRawY();
239
- }
240
- break;
241
- case MotionEvent.ACTION_MOVE:
242
- x = (int) event.getRawX();
243
- y = (int) event.getRawY();
244
-
245
- final float dx = x - mLastTouchX;
246
- final float dy = y - mLastTouchY;
247
-
248
- mPosX += dx;
249
- mPosY += dy;
250
-
251
- layoutParams.leftMargin = mPosX;
252
- layoutParams.topMargin = mPosY;
253
-
254
- frameContainerLayout.setLayoutParams(layoutParams);
255
-
256
- // Remember this touch position for the next move event
257
- mLastTouchX = x;
258
- mLastTouchY = y;
259
-
260
- break;
261
- default:
262
- break;
263
- }
264
- }
265
- }
266
- }
267
- return true;
268
- }
269
- }
270
- );
271
- frameContainerLayout.setFocusableInTouchMode(true);
272
- frameContainerLayout.requestFocus();
273
- // this was swallowing the back button events
274
- // frameContainerLayout.setOnKeyListener(
275
- // new View.OnKeyListener() {
276
- // @Override
277
- // public boolean onKey(View v, int keyCode, android.view.KeyEvent event) {
278
- // if (keyCode == android.view.KeyEvent.KEYCODE_BACK) {
279
- // eventListener.onBackButton();
280
- // return true;
281
- // }
282
- // return false;
283
- // }
284
- // }
285
- // );
286
- }
287
-
288
- private float mDist = 0F;
289
-
290
- private void handleZoom(MotionEvent event, Camera.Parameters params) {
291
- if (mCamera != null) {
292
- mCamera.cancelAutoFocus();
293
- int maxZoom = params.getMaxZoom();
294
- int zoom = params.getZoom();
295
- float newDist = getFingerSpacing(event);
296
- if (newDist > mDist) {
297
- //zoom in
298
- if (zoom < maxZoom) zoom++;
299
- } else if (newDist < mDist) {
300
- //zoom out
301
- if (zoom > 0) zoom--;
302
- // zoom again if possible, users report that zooming out felt slower than zooming in
303
- if (zoom > 0) zoom--;
304
- }
305
- mDist = newDist;
306
- params.setZoom(zoom);
307
- mCamera.setParameters(params);
308
- }
309
- }
310
- }
311
- );
312
- }
313
-
314
- private void setDefaultCameraId() {
315
- // Find the total number of cameras available
316
- numberOfCameras = Camera.getNumberOfCameras();
317
-
318
- int facing = "front".equals(defaultCamera) ? Camera.CameraInfo.CAMERA_FACING_FRONT : Camera.CameraInfo.CAMERA_FACING_BACK;
319
-
320
- // Find the ID of the default camera
321
- Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
322
- for (int i = 0; i < numberOfCameras; i++) {
323
- Camera.getCameraInfo(i, cameraInfo);
324
- if (cameraInfo.facing == facing) {
325
- defaultCameraId = i;
326
- break;
327
- }
328
- }
329
- }
330
-
331
- @Override
332
- public void onResume() {
333
- super.onResume();
334
-
335
- mCamera = Camera.open(defaultCameraId);
336
-
337
- if (cameraParameters != null) {
338
- mCamera.setParameters(cameraParameters);
339
- }
340
-
341
- cameraCurrentlyLocked = defaultCameraId;
342
-
343
- if (mPreview.mPreviewSize == null) {
344
- mPreview.setCamera(mCamera, cameraCurrentlyLocked);
345
- eventListener.onCameraStarted();
346
- } else {
347
- mPreview.switchCamera(mCamera, cameraCurrentlyLocked);
348
- mCamera.startPreview();
349
- }
350
-
351
- Log.d(TAG, "cameraCurrentlyLocked:" + cameraCurrentlyLocked);
352
-
353
- final FrameLayout frameContainerLayout = (FrameLayout) view.findViewById(
354
- getResources().getIdentifier("frame_container", "id", appResourcesPackage)
355
- );
356
-
357
- ViewTreeObserver viewTreeObserver = frameContainerLayout.getViewTreeObserver();
358
-
359
- if (viewTreeObserver.isAlive()) {
360
- viewTreeObserver.addOnGlobalLayoutListener(
361
- new ViewTreeObserver.OnGlobalLayoutListener() {
362
- @Override
363
- public void onGlobalLayout() {
364
- frameContainerLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
365
- frameContainerLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
366
- Activity activity = getActivity();
367
- if (isAdded() && activity != null) {
368
- final RelativeLayout frameCamContainerLayout = (RelativeLayout) view.findViewById(
369
- getResources().getIdentifier("frame_camera_cont", "id", appResourcesPackage)
370
- );
371
-
372
- FrameLayout.LayoutParams camViewLayout = new FrameLayout.LayoutParams(
373
- frameContainerLayout.getWidth(),
374
- frameContainerLayout.getHeight()
375
- );
376
- camViewLayout.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
377
- frameCamContainerLayout.setLayoutParams(camViewLayout);
378
- }
379
- }
380
- }
381
- );
382
- }
383
- }
384
-
385
- @Override
386
- public void onPause() {
387
- super.onPause();
388
-
389
- // Because the Camera object is a shared resource, it's very important to release it when the activity is paused.
390
- if (mCamera != null) {
391
- setDefaultCameraId();
392
- mPreview.setCamera(null, -1);
393
- mCamera.setPreviewCallback(null);
394
- mCamera.release();
395
- mCamera = null;
396
- }
397
- }
398
-
399
- @Override
400
- public void onConfigurationChanged(Configuration newConfig) {
401
- super.onConfigurationChanged(newConfig);
402
-
403
- final FrameLayout frameContainerLayout = (FrameLayout) view.findViewById(
404
- getResources().getIdentifier("frame_container", "id", appResourcesPackage)
405
- );
406
-
407
- final int previousOrientation = frameContainerLayout.getHeight() > frameContainerLayout.getWidth() ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
408
- // Checks if the orientation of the screen has changed
409
- if (newConfig.orientation != previousOrientation) {
410
-
411
- final RelativeLayout frameCamContainerLayout = (RelativeLayout) view.findViewById(
412
- getResources().getIdentifier("frame_camera_cont", "id", appResourcesPackage)
413
- );
414
-
415
- frameContainerLayout.getLayoutParams().width = frameCamContainerLayout.getHeight();
416
- frameContainerLayout.getLayoutParams().height = frameCamContainerLayout.getWidth();
417
-
418
- frameCamContainerLayout.getLayoutParams().width = frameCamContainerLayout.getHeight();
419
- frameCamContainerLayout.getLayoutParams().height = frameCamContainerLayout.getWidth();
420
-
421
- frameContainerLayout.invalidate();
422
- frameContainerLayout.requestLayout();
423
-
424
- frameCamContainerLayout.forceLayout();
425
-
426
- mPreview.setCameraDisplayOrientation();
427
-
428
- }
429
-
430
- }
431
-
432
-
433
- public Camera getCamera() {
434
- return mCamera;
435
- }
436
-
437
- public void switchCamera() {
438
- // check for availability of multiple cameras
439
- if (numberOfCameras == 1) {
440
- //There is only one camera available
441
- } else {
442
- Log.d(TAG, "numberOfCameras: " + numberOfCameras);
443
-
444
- // OK, we have multiple cameras. Release this camera -> cameraCurrentlyLocked
445
- if (mCamera != null) {
446
- mCamera.stopPreview();
447
- mPreview.setCamera(null, -1);
448
- mCamera.release();
449
- mCamera = null;
450
- }
451
-
452
- Log.d(TAG, "cameraCurrentlyLocked := " + Integer.toString(cameraCurrentlyLocked));
453
- try {
454
- cameraCurrentlyLocked = (cameraCurrentlyLocked + 1) % numberOfCameras;
455
- Log.d(TAG, "cameraCurrentlyLocked new: " + cameraCurrentlyLocked);
456
- } catch (Exception exception) {
457
- Log.d(TAG, exception.getMessage());
458
- }
459
-
460
- // Acquire the next camera and request Preview to reconfigure parameters.
461
- mCamera = Camera.open(cameraCurrentlyLocked);
462
-
463
- if (cameraParameters != null) {
464
- Log.d(TAG, "camera parameter not null");
465
-
466
- // Check for flashMode as well to prevent error on frontward facing camera.
467
- List<String> supportedFlashModesNewCamera = mCamera.getParameters().getSupportedFlashModes();
468
- String currentFlashModePreviousCamera = cameraParameters.getFlashMode();
469
- if (supportedFlashModesNewCamera != null && supportedFlashModesNewCamera.contains(currentFlashModePreviousCamera)) {
470
- Log.d(TAG, "current flash mode supported on new camera. setting params");
471
- /* mCamera.setParameters(cameraParameters);
472
- The line above is disabled because parameters that can actually be changed are different from one device to another. Makes less sense trying to reconfigure them when changing camera device while those settings gan be changed using plugin methods.
473
- */
474
- } else {
475
- Log.d(TAG, "current flash mode NOT supported on new camera");
476
- }
477
- } else {
478
- Log.d(TAG, "camera parameter NULL");
479
- }
480
-
481
- mPreview.switchCamera(mCamera, cameraCurrentlyLocked);
482
-
483
- mCamera.startPreview();
484
- }
485
- }
486
-
487
- public void setCameraParameters(Camera.Parameters params) {
488
- cameraParameters = params;
489
-
490
- if (mCamera != null && cameraParameters != null) {
491
- mCamera.setParameters(cameraParameters);
492
- }
493
- }
494
-
495
- public boolean hasFrontCamera() {
496
- return getActivity().getApplicationContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
497
- }
498
-
499
- public static Bitmap applyMatrix(Bitmap source, Matrix matrix) {
500
- return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
501
- }
502
-
503
- ShutterCallback shutterCallback = new ShutterCallback() {
504
- public void onShutter() {
505
- // do nothing, availabilty of this callback causes default system shutter sound to work
506
- }
507
- };
508
-
509
- private static int exifToDegrees(int exifOrientation) {
510
- if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) {
511
- return 90;
512
- } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {
513
- return 180;
514
- } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
515
- return 270;
516
- }
517
- return 0;
518
- }
519
-
520
- private String getTempDirectoryPath() {
521
- File cache = null;
522
-
523
- // Use internal storage
524
- cache = getActivity().getCacheDir();
525
-
526
- // Create the cache directory if it doesn't exist
527
- cache.mkdirs();
528
- return cache.getAbsolutePath();
529
- }
530
-
531
- private String getTempFilePath() {
532
- return getTempDirectoryPath() + "/cpcp_capture_" + UUID.randomUUID().toString().replace("-", "").substring(0, 8) + ".jpg";
533
- }
534
-
535
- PictureCallback jpegPictureCallback = new PictureCallback() {
536
- public void onPictureTaken(byte[] data, Camera arg1) {
537
- Log.d(TAG, "CameraPreview jpegPictureCallback");
538
-
539
- try {
540
- if (!disableExifHeaderStripping) {
541
- Matrix matrix = new Matrix();
542
- if (cameraCurrentlyLocked == Camera.CameraInfo.CAMERA_FACING_FRONT) {
543
- matrix.preScale(1.0f, -1.0f);
544
- }
545
-
546
- ExifInterface exifInterface = new ExifInterface(new ByteArrayInputStream(data));
547
- int rotation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
548
- int rotationInDegrees = exifToDegrees(rotation);
549
-
550
- if (rotation != 0f) {
551
- matrix.preRotate(rotationInDegrees);
552
- }
553
-
554
- // Check if matrix has changed. In that case, apply matrix and override data
555
- if (!matrix.isIdentity()) {
556
- Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
557
- bitmap = applyMatrix(bitmap, matrix);
558
-
559
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
560
- bitmap.compress(CompressFormat.JPEG, currentQuality, outputStream);
561
- data = outputStream.toByteArray();
562
- }
563
- }
564
-
565
- if (!storeToFile) {
566
- String encodedImage = Base64.encodeToString(data, Base64.NO_WRAP);
567
-
568
- eventListener.onPictureTaken(encodedImage);
569
- } else {
570
- String path = getTempFilePath();
571
- FileOutputStream out = new FileOutputStream(path);
572
- out.write(data);
573
- out.close();
574
- eventListener.onPictureTaken(path);
575
- }
576
- Log.d(TAG, "CameraPreview pictureTakenHandler called back");
577
- } catch (OutOfMemoryError e) {
578
- // most likely failed to allocate memory for rotateBitmap
579
- Log.d(TAG, "CameraPreview OutOfMemoryError");
580
- // failed to allocate memory
581
- eventListener.onPictureTakenError("Picture too large (memory)");
582
- } catch (IOException e) {
583
- Log.d(TAG, "CameraPreview IOException");
584
- eventListener.onPictureTakenError("IO Error when extracting exif");
585
- } catch (Exception e) {
586
- Log.d(TAG, "CameraPreview onPictureTaken general exception");
587
- } finally {
588
- canTakePicture = true;
589
- mCamera.startPreview();
590
- }
591
- }
592
- };
593
-
594
- private Camera.Size getOptimalPictureSize(
595
- final int width,
596
- final int height,
597
- final Camera.Size previewSize,
598
- final List<Camera.Size> supportedSizes
599
- ) {
600
- /*
601
- get the supportedPictureSize that:
602
- - matches exactly width and height
603
- - has the closest aspect ratio to the preview aspect ratio
604
- - has picture.width and picture.height closest to width and height
605
- - has the highest supported picture width and height up to 2 Megapixel if width == 0 || height == 0
606
- */
607
- Camera.Size size = mCamera.new Size(width, height);
608
-
609
- // convert to landscape if necessary
610
- if (size.width < size.height) {
611
- int temp = size.width;
612
- size.width = size.height;
613
- size.height = temp;
614
- }
615
-
616
- Camera.Size requestedSize = mCamera.new Size(size.width, size.height);
617
-
618
- double previewAspectRatio = (double) previewSize.width / (double) previewSize.height;
619
-
620
- if (previewAspectRatio < 1.0) {
621
- // reset ratio to landscape
622
- previewAspectRatio = 1.0 / previewAspectRatio;
623
- }
624
-
625
- Log.d(TAG, "CameraPreview previewAspectRatio " + previewAspectRatio);
626
-
627
- double aspectTolerance = 0.1;
628
- double bestDifference = Double.MAX_VALUE;
629
-
630
- for (int i = 0; i < supportedSizes.size(); i++) {
631
- Camera.Size supportedSize = supportedSizes.get(i);
632
-
633
- // Perfect match
634
- if (supportedSize.equals(requestedSize)) {
635
- Log.d(TAG, "CameraPreview optimalPictureSize " + supportedSize.width + 'x' + supportedSize.height);
636
- return supportedSize;
637
- }
638
-
639
- double difference = Math.abs(previewAspectRatio - ((double) supportedSize.width / (double) supportedSize.height));
640
-
641
- if (difference < bestDifference - aspectTolerance) {
642
- // better aspectRatio found
643
- if ((width != 0 && height != 0) || (supportedSize.width * supportedSize.height < 2048 * 1024)) {
644
- size.width = supportedSize.width;
645
- size.height = supportedSize.height;
646
- bestDifference = difference;
647
- }
648
- } else if (difference < bestDifference + aspectTolerance) {
649
- // same aspectRatio found (within tolerance)
650
- if (width == 0 || height == 0) {
651
- // set highest supported resolution below 2 Megapixel
652
- if ((size.width < supportedSize.width) && (supportedSize.width * supportedSize.height < 2048 * 1024)) {
653
- size.width = supportedSize.width;
654
- size.height = supportedSize.height;
655
- }
656
- } else {
657
- // check if this pictureSize closer to requested width and height
658
- if (
659
- Math.abs(width * height - supportedSize.width * supportedSize.height) <
660
- Math.abs(width * height - size.width * size.height)
661
- ) {
662
- size.width = supportedSize.width;
663
- size.height = supportedSize.height;
664
- }
665
- }
666
- }
667
- }
668
- Log.d(TAG, "CameraPreview optimalPictureSize " + size.width + 'x' + size.height);
669
- return size;
670
- }
671
-
672
- static byte[] rotateNV21(final byte[] yuv, final int width, final int height, final int rotation) {
673
- if (rotation == 0) return yuv;
674
- if (rotation % 90 != 0 || rotation < 0 || rotation > 270) {
675
- throw new IllegalArgumentException("0 <= rotation < 360, rotation % 90 == 0");
676
- }
677
-
678
- final byte[] output = new byte[yuv.length];
679
- final int frameSize = width * height;
680
- final boolean swap = rotation % 180 != 0;
681
- final boolean xflip = rotation % 270 != 0;
682
- final boolean yflip = rotation >= 180;
683
-
684
- for (int j = 0; j < height; j++) {
685
- for (int i = 0; i < width; i++) {
686
- final int yIn = j * width + i;
687
- final int uIn = frameSize + (j >> 1) * width + (i & ~1);
688
- final int vIn = uIn + 1;
689
-
690
- final int wOut = swap ? height : width;
691
- final int hOut = swap ? width : height;
692
- final int iSwapped = swap ? j : i;
693
- final int jSwapped = swap ? i : j;
694
- final int iOut = xflip ? wOut - iSwapped - 1 : iSwapped;
695
- final int jOut = yflip ? hOut - jSwapped - 1 : jSwapped;
696
-
697
- final int yOut = jOut * wOut + iOut;
698
- final int uOut = frameSize + (jOut >> 1) * wOut + (iOut & ~1);
699
- final int vOut = uOut + 1;
700
-
701
- output[yOut] = (byte) (0xff & yuv[yIn]);
702
- output[uOut] = (byte) (0xff & yuv[uIn]);
703
- output[vOut] = (byte) (0xff & yuv[vIn]);
704
- }
705
- }
706
- return output;
707
- }
708
-
709
- public void setOpacity(final float opacity) {
710
- Log.d(TAG, "set opacity:" + opacity);
711
- this.opacity = opacity;
712
- mPreview.setOpacity(opacity);
713
- }
714
-
715
- public void takeSnapshot(final int quality) {
716
- mCamera.setPreviewCallback(
717
- new Camera.PreviewCallback() {
718
- @Override
719
- public void onPreviewFrame(byte[] bytes, Camera camera) {
720
- try {
721
- Camera.Parameters parameters = camera.getParameters();
722
- Camera.Size size = parameters.getPreviewSize();
723
- int orientation = mPreview.getDisplayOrientation();
724
- if (mPreview.getCameraFacing() == Camera.CameraInfo.CAMERA_FACING_FRONT) {
725
- bytes = rotateNV21(bytes, size.width, size.height, (360 - orientation) % 360);
726
- } else {
727
- bytes = rotateNV21(bytes, size.width, size.height, orientation);
728
- }
729
- // switch width/height when rotating 90/270 deg
730
- Rect rect = orientation == 90 || orientation == 270
731
- ? new Rect(0, 0, size.height, size.width)
732
- : new Rect(0, 0, size.width, size.height);
733
- YuvImage yuvImage = new YuvImage(bytes, parameters.getPreviewFormat(), rect.width(), rect.height(), null);
734
- ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
735
- yuvImage.compressToJpeg(rect, quality, byteArrayOutputStream);
736
- byte[] data = byteArrayOutputStream.toByteArray();
737
- byteArrayOutputStream.close();
738
- eventListener.onSnapshotTaken(Base64.encodeToString(data, Base64.NO_WRAP));
739
- } catch (IOException e) {
740
- Log.d(TAG, "CameraPreview IOException");
741
- eventListener.onSnapshotTakenError("IO Error");
742
- } finally {
743
- mCamera.setPreviewCallback(null);
744
- }
745
- }
746
- }
747
- );
748
- }
749
-
750
- public void takePicture(final int width, final int height, final int quality) {
751
- Log.d(TAG, "CameraPreview takePicture width: " + width + ", height: " + height + ", quality: " + quality);
752
-
753
- if (mPreview != null) {
754
- if (!canTakePicture) {
755
- return;
756
- }
757
-
758
- canTakePicture = false;
759
-
760
- new Thread() {
761
- public void run() {
762
- Camera.Parameters params = mCamera.getParameters();
763
-
764
- Camera.Size size = getOptimalPictureSize(width, height, params.getPreviewSize(), params.getSupportedPictureSizes());
765
- params.setPictureSize(size.width, size.height);
766
- currentQuality = quality;
767
-
768
- if (cameraCurrentlyLocked == Camera.CameraInfo.CAMERA_FACING_FRONT && !storeToFile) {
769
- // The image will be recompressed in the callback
770
- params.setJpegQuality(99);
771
- } else {
772
- params.setJpegQuality(quality);
773
- }
774
-
775
- if (cameraCurrentlyLocked == Camera.CameraInfo.CAMERA_FACING_FRONT && disableExifHeaderStripping) {
776
- Activity activity = getActivity();
777
- int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
778
- int degrees = 0;
779
- switch (rotation) {
780
- case Surface.ROTATION_0:
781
- degrees = 0;
782
- break;
783
- case Surface.ROTATION_90:
784
- degrees = 180;
785
- break;
786
- case Surface.ROTATION_180:
787
- degrees = 270;
788
- break;
789
- case Surface.ROTATION_270:
790
- degrees = 0;
791
- break;
792
- }
793
- int orientation;
794
- Camera.CameraInfo info = new Camera.CameraInfo();
795
- if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
796
- orientation = (info.orientation + degrees) % 360;
797
- if (degrees != 0) {
798
- orientation = (360 - orientation) % 360;
799
- }
800
- } else {
801
- orientation = (info.orientation - degrees + 360) % 360;
802
- }
803
- params.setRotation(orientation);
804
- } else {
805
- params.setRotation(mPreview.getDisplayOrientation());
806
- }
807
-
808
- mCamera.setParameters(params);
809
- mCamera.takePicture(shutterCallback, null, jpegPictureCallback);
810
- }
811
- }
812
- .start();
813
- } else {
814
- canTakePicture = true;
815
- }
816
- }
817
-
818
- public void startRecord(
819
- final String filePath,
820
- final String camera,
821
- final int width,
822
- final int height,
823
- final int quality,
824
- final boolean withFlash,
825
- final int maxDuration,
826
- final String lens
827
- ) {
828
- Log.d(TAG, "CameraPreview startRecord camera: " + camera + " width: " + width + ", height: " + height + ", quality: " + quality + ", lens: " + lens);
829
- Activity activity = getActivity();
830
- muteStream(true, activity);
831
- if (this.mRecordingState == RecordingState.STARTED) {
832
- Log.d(TAG, "Already Recording");
833
- return;
834
- }
835
-
836
- this.recordFilePath = filePath;
837
- int mOrientationHint = calculateOrientationHint();
838
- int videoWidth = 0; //set whatever
839
- int videoHeight = 0; //set whatever
840
-
841
- Camera.Parameters cameraParams = mCamera.getParameters();
842
- if (withFlash) {
843
- cameraParams.setFlashMode(withFlash ? Camera.Parameters.FLASH_MODE_TORCH : Camera.Parameters.FLASH_MODE_OFF);
844
- mCamera.setParameters(cameraParams);
845
- mCamera.startPreview();
846
- }
847
-
848
- mCamera.unlock();
849
- mRecorder = new MediaRecorder();
850
-
851
- try {
852
- mRecorder.setCamera(mCamera);
853
-
854
- CamcorderProfile profile;
855
- if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_HIGH)) {
856
- profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_HIGH);
857
- } else {
858
- if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_480P)) {
859
- profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_480P);
860
- } else {
861
- if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_720P)) {
862
- profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_720P);
863
- } else {
864
- if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_1080P)) {
865
- profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_1080P);
866
- } else {
867
- profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_LOW);
868
- }
869
- }
870
- }
871
- }
872
-
873
- mRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_RECOGNITION);
874
- mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
875
- mRecorder.setProfile(profile);
876
- mRecorder.setOutputFile(filePath);
877
- mRecorder.setOrientationHint(mOrientationHint);
878
- mRecorder.setMaxDuration(maxDuration);
879
-
880
- mRecorder.prepare();
881
- Log.d(TAG, "Starting recording");
882
- mRecorder.start();
883
- eventListener.onStartRecordVideo();
884
- } catch (IOException e) {
885
- eventListener.onStartRecordVideoError(e.getMessage());
886
- }
887
- }
888
-
889
- public int calculateOrientationHint() {
890
- DisplayMetrics dm = new DisplayMetrics();
891
- Camera.CameraInfo info = new Camera.CameraInfo();
892
- Camera.getCameraInfo(defaultCameraId, info);
893
- int cameraRotationOffset = info.orientation;
894
- Activity activity = getActivity();
895
-
896
- activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
897
- int currentScreenRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
898
-
899
- int degrees = 0;
900
- switch (currentScreenRotation) {
901
- case Surface.ROTATION_0:
902
- degrees = 0;
903
- break;
904
- case Surface.ROTATION_90:
905
- degrees = 90;
906
- break;
907
- case Surface.ROTATION_180:
908
- degrees = 180;
909
- break;
910
- case Surface.ROTATION_270:
911
- degrees = 270;
912
- break;
913
- }
914
-
915
- int orientation;
916
- if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
917
- orientation = (cameraRotationOffset + degrees) % 360;
918
- if (degrees != 0) {
919
- orientation = (360 - orientation) % 360;
920
- }
921
- } else {
922
- orientation = (cameraRotationOffset - degrees + 360) % 360;
923
- }
924
- Log.w(TAG, "************orientationHint ***********= " + orientation);
925
-
926
- return orientation;
927
- }
928
-
929
- public void stopRecord() {
930
- Log.d(TAG, "stopRecord");
931
-
932
- try {
933
- mRecorder.stop();
934
- mRecorder.reset(); // clear recorder configuration
935
- mRecorder.release(); // release the recorder object
936
- mRecorder = null;
937
- mCamera.lock();
938
- Camera.Parameters cameraParams = mCamera.getParameters();
939
- cameraParams.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
940
- mCamera.setParameters(cameraParams);
941
- mCamera.startPreview();
942
- eventListener.onStopRecordVideo(this.recordFilePath);
943
- } catch (Exception e) {
944
- eventListener.onStopRecordVideoError(e.getMessage());
945
- }
946
- }
947
-
948
- public void muteStream(boolean mute, Activity activity) {
949
- AudioManager audioManager = ((AudioManager) activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE));
950
- int direction = mute ? audioManager.ADJUST_MUTE : audioManager.ADJUST_UNMUTE;
951
- }
952
-
953
- public void setFocusArea(final int pointX, final int pointY, final Camera.AutoFocusCallback callback) {
954
- if (mCamera != null) {
955
- mCamera.cancelAutoFocus();
956
-
957
- Camera.Parameters parameters = mCamera.getParameters();
958
-
959
- Rect focusRect = calculateTapArea(pointX, pointY, 1f);
960
- parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
961
- parameters.setFocusAreas(Arrays.asList(new Camera.Area(focusRect, 1000)));
962
-
963
- if (parameters.getMaxNumMeteringAreas() > 0) {
964
- Rect meteringRect = calculateTapArea(pointX, pointY, 1.5f);
965
- parameters.setMeteringAreas(Arrays.asList(new Camera.Area(meteringRect, 1000)));
966
- }
967
-
968
- try {
969
- setCameraParameters(parameters);
970
- mCamera.autoFocus(callback);
971
- } catch (Exception e) {
972
- Log.d(TAG, e.getMessage());
973
- callback.onAutoFocus(false, this.mCamera);
974
- }
975
- }
976
- }
977
-
978
- private Rect calculateTapArea(float x, float y, float coefficient) {
979
- if (x < 100) {
980
- x = 100;
981
- }
982
- if (x > width - 100) {
983
- x = width - 100;
984
- }
985
- if (y < 100) {
986
- y = 100;
987
- }
988
- if (y > height - 100) {
989
- y = height - 100;
990
- }
991
- return new Rect(
992
- Math.round((x - 100) * 2000 / width - 1000),
993
- Math.round((y - 100) * 2000 / height - 1000),
994
- Math.round((x + 100) * 2000 / width - 1000),
995
- Math.round((y + 100) * 2000 / height - 1000)
996
- );
997
- }
998
-
999
- /**
1000
- * Determine the space between the first two fingers
1001
- */
1002
- private static float getFingerSpacing(MotionEvent event) {
1003
- // ...
1004
- float x = event.getX(0) - event.getX(1);
1005
- float y = event.getY(0) - event.getY(1);
1006
- return (float) Math.sqrt(x * x + y * y);
1007
- }
1008
- }
1
+ package com.ahm.capacitor.camera.preview;
2
+
3
+ import android.app.Activity;
4
+ import android.app.Fragment;
5
+ import android.content.Context;
6
+ import android.content.pm.PackageManager;
7
+ import android.content.res.Configuration;
8
+ import android.graphics.Bitmap;
9
+ import android.graphics.Bitmap.CompressFormat;
10
+ import android.graphics.BitmapFactory;
11
+ import android.graphics.Canvas;
12
+ import android.graphics.ImageFormat;
13
+ import android.graphics.Matrix;
14
+ import android.graphics.Rect;
15
+ import android.graphics.YuvImage;
16
+ import android.hardware.Camera;
17
+ import android.hardware.Camera.PictureCallback;
18
+ import android.hardware.Camera.ShutterCallback;
19
+ import android.hardware.camera2.CameraManager;
20
+ import android.media.AudioManager;
21
+ import android.media.CamcorderProfile;
22
+ import android.media.MediaRecorder;
23
+ import android.os.Bundle;
24
+ import android.util.Base64;
25
+ import android.util.DisplayMetrics;
26
+ import android.util.Log;
27
+ import android.view.GestureDetector;
28
+ import android.view.Gravity;
29
+ import android.view.LayoutInflater;
30
+ import android.view.MotionEvent;
31
+ import android.view.Surface;
32
+ import android.view.Surface;
33
+ import android.view.SurfaceHolder;
34
+ import android.view.SurfaceView;
35
+ import android.view.View;
36
+ import android.view.ViewGroup;
37
+ import android.view.ViewTreeObserver;
38
+ import android.widget.FrameLayout;
39
+ import android.widget.RelativeLayout;
40
+ import androidx.exifinterface.media.ExifInterface;
41
+ import java.io.ByteArrayInputStream;
42
+ import java.io.ByteArrayOutputStream;
43
+ import java.io.File;
44
+ import java.io.FileOutputStream;
45
+ import java.io.IOException;
46
+ import java.util.Arrays;
47
+ import java.util.List;
48
+ import java.util.UUID;
49
+
50
+ public class CameraActivity extends Fragment {
51
+
52
+ public interface CameraPreviewListener {
53
+ void onPictureTaken(String originalPicture);
54
+ void onPictureTakenError(String message);
55
+ void onSnapshotTaken(String originalPicture);
56
+ void onSnapshotTakenError(String message);
57
+ void onFocusSet(int pointX, int pointY);
58
+ void onFocusSetError(String message);
59
+ void onBackButton();
60
+ void onCameraStarted();
61
+ void onStartRecordVideo();
62
+ void onStartRecordVideoError(String message);
63
+ void onStopRecordVideo(String file);
64
+ void onStopRecordVideoError(String error);
65
+ }
66
+
67
+ private CameraPreviewListener eventListener;
68
+ private static final String TAG = "CameraActivity";
69
+ public FrameLayout mainLayout;
70
+ public FrameLayout frameContainerLayout;
71
+
72
+ private Preview mPreview;
73
+ private boolean canTakePicture = true;
74
+
75
+ private View view;
76
+ private Camera.Parameters cameraParameters;
77
+ private Camera mCamera;
78
+ private int numberOfCameras;
79
+ private int cameraCurrentlyLocked;
80
+ private int currentQuality;
81
+
82
+ private enum RecordingState {
83
+ INITIALIZING,
84
+ STARTED,
85
+ STOPPED
86
+ }
87
+
88
+ private RecordingState mRecordingState = RecordingState.INITIALIZING;
89
+ private MediaRecorder mRecorder = null;
90
+ private String recordFilePath;
91
+ private float opacity;
92
+
93
+ // The first rear facing camera
94
+ private int defaultCameraId;
95
+ public String defaultCamera;
96
+ public boolean tapToTakePicture;
97
+ public boolean dragEnabled;
98
+ public boolean tapToFocus;
99
+ public boolean disableExifHeaderStripping;
100
+ public boolean storeToFile;
101
+ public boolean toBack;
102
+ public boolean enableOpacity = false;
103
+ public boolean enableZoom = false;
104
+
105
+ public int width;
106
+ public int height;
107
+ public int x;
108
+ public int y;
109
+
110
+ public void setEventListener(CameraPreviewListener listener) {
111
+ eventListener = listener;
112
+ }
113
+
114
+ private String appResourcesPackage;
115
+
116
+ @Override
117
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
118
+ appResourcesPackage = getActivity().getPackageName();
119
+
120
+ // Inflate the layout for this fragment
121
+ view = inflater.inflate(getResources().getIdentifier("camera_activity", "layout", appResourcesPackage), container, false);
122
+ createCameraPreview();
123
+ return view;
124
+ }
125
+
126
+ public void setRect(int x, int y, int width, int height) {
127
+ this.x = x;
128
+ this.y = y;
129
+ this.width = width;
130
+ this.height = height;
131
+ }
132
+
133
+ private void createCameraPreview() {
134
+ if (mPreview == null) {
135
+ setDefaultCameraId();
136
+
137
+ //set box position and size
138
+ FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(width, height);
139
+ layoutParams.setMargins(x, y, 0, 0);
140
+ frameContainerLayout =
141
+ (FrameLayout) view.findViewById(getResources().getIdentifier("frame_container", "id", appResourcesPackage));
142
+ frameContainerLayout.setLayoutParams(layoutParams);
143
+
144
+ //video view
145
+ mPreview = new Preview(getActivity(), enableOpacity);
146
+ mainLayout = (FrameLayout) view.findViewById(getResources().getIdentifier("video_view", "id", appResourcesPackage));
147
+ mainLayout.setLayoutParams(
148
+ new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
149
+ );
150
+ mainLayout.addView(mPreview);
151
+ mainLayout.setEnabled(false);
152
+
153
+ if (enableZoom) {
154
+ this.setupTouchAndBackButton();
155
+ }
156
+ }
157
+ }
158
+
159
+ private void setupTouchAndBackButton() {
160
+ final GestureDetector gestureDetector = new GestureDetector(getActivity().getApplicationContext(), new TapGestureDetector());
161
+
162
+ getActivity()
163
+ .runOnUiThread(
164
+ new Runnable() {
165
+ @Override
166
+ public void run() {
167
+ frameContainerLayout.setClickable(true);
168
+ frameContainerLayout.setOnTouchListener(
169
+ new View.OnTouchListener() {
170
+ private int mLastTouchX;
171
+ private int mLastTouchY;
172
+ private int mPosX = 0;
173
+ private int mPosY = 0;
174
+
175
+ @Override
176
+ public boolean onTouch(View v, MotionEvent event) {
177
+ FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) frameContainerLayout.getLayoutParams();
178
+
179
+ boolean isSingleTapTouch = gestureDetector.onTouchEvent(event);
180
+ int action = event.getAction();
181
+ int eventCount = event.getPointerCount();
182
+ Log.d(TAG, "onTouch event, action, count: " + event + ", " + action + ", " + eventCount);
183
+ if (eventCount > 1) {
184
+ // handle multi-touch events
185
+ Camera.Parameters params = mCamera.getParameters();
186
+ if (action == MotionEvent.ACTION_POINTER_DOWN) {
187
+ mDist = getFingerSpacing(event);
188
+ } else if (action == MotionEvent.ACTION_MOVE && params.isZoomSupported()) {
189
+ handleZoom(event, params);
190
+ }
191
+ } else {
192
+ if (action != MotionEvent.ACTION_MOVE && isSingleTapTouch) {
193
+ if (tapToTakePicture && tapToFocus) {
194
+ setFocusArea(
195
+ (int) event.getX(0),
196
+ (int) event.getY(0),
197
+ new Camera.AutoFocusCallback() {
198
+ public void onAutoFocus(boolean success, Camera camera) {
199
+ if (success) {
200
+ takePicture(0, 0, 85);
201
+ } else {
202
+ Log.d(TAG, "onTouch:" + " setFocusArea() did not suceed");
203
+ }
204
+ }
205
+ }
206
+ );
207
+ } else if (tapToTakePicture) {
208
+ takePicture(0, 0, 85);
209
+ } else if (tapToFocus) {
210
+ setFocusArea(
211
+ (int) event.getX(0),
212
+ (int) event.getY(0),
213
+ new Camera.AutoFocusCallback() {
214
+ public void onAutoFocus(boolean success, Camera camera) {
215
+ if (success) {
216
+ // A callback to JS might make sense here.
217
+ } else {
218
+ Log.d(TAG, "onTouch:" + " setFocusArea() did not suceed");
219
+ }
220
+ }
221
+ }
222
+ );
223
+ }
224
+ return true;
225
+ } else {
226
+ if (dragEnabled) {
227
+ int x;
228
+ int y;
229
+
230
+ switch (event.getAction()) {
231
+ case MotionEvent.ACTION_DOWN:
232
+ if (mLastTouchX == 0 || mLastTouchY == 0) {
233
+ mLastTouchX = (int) event.getRawX() - layoutParams.leftMargin;
234
+ mLastTouchY = (int) event.getRawY() - layoutParams.topMargin;
235
+ } else {
236
+ mLastTouchX = (int) event.getRawX();
237
+ mLastTouchY = (int) event.getRawY();
238
+ }
239
+ break;
240
+ case MotionEvent.ACTION_MOVE:
241
+ x = (int) event.getRawX();
242
+ y = (int) event.getRawY();
243
+
244
+ final float dx = x - mLastTouchX;
245
+ final float dy = y - mLastTouchY;
246
+
247
+ mPosX += dx;
248
+ mPosY += dy;
249
+
250
+ layoutParams.leftMargin = mPosX;
251
+ layoutParams.topMargin = mPosY;
252
+
253
+ frameContainerLayout.setLayoutParams(layoutParams);
254
+
255
+ // Remember this touch position for the next move event
256
+ mLastTouchX = x;
257
+ mLastTouchY = y;
258
+
259
+ break;
260
+ default:
261
+ break;
262
+ }
263
+ }
264
+ }
265
+ }
266
+ return true;
267
+ }
268
+ }
269
+ );
270
+ frameContainerLayout.setFocusableInTouchMode(true);
271
+ frameContainerLayout.requestFocus();
272
+ // this was swallowing the back button events
273
+ // frameContainerLayout.setOnKeyListener(
274
+ // new View.OnKeyListener() {
275
+ // @Override
276
+ // public boolean onKey(View v, int keyCode, android.view.KeyEvent event) {
277
+ // if (keyCode == android.view.KeyEvent.KEYCODE_BACK) {
278
+ // eventListener.onBackButton();
279
+ // return true;
280
+ // }
281
+ // return false;
282
+ // }
283
+ // }
284
+ // );
285
+ }
286
+
287
+ private float mDist = 0F;
288
+
289
+ private void handleZoom(MotionEvent event, Camera.Parameters params) {
290
+ if (mCamera != null) {
291
+ mCamera.cancelAutoFocus();
292
+ int maxZoom = params.getMaxZoom();
293
+ int zoom = params.getZoom();
294
+ float newDist = getFingerSpacing(event);
295
+ if (newDist > mDist) {
296
+ //zoom in
297
+ if (zoom < maxZoom) zoom++;
298
+ } else if (newDist < mDist) {
299
+ //zoom out
300
+ if (zoom > 0) zoom--;
301
+ // zoom again if possible, users report that zooming out felt slower than zooming in
302
+ if (zoom > 0) zoom--;
303
+ }
304
+ mDist = newDist;
305
+ params.setZoom(zoom);
306
+ mCamera.setParameters(params);
307
+ }
308
+ }
309
+ }
310
+ );
311
+ }
312
+
313
+ private void setDefaultCameraId() {
314
+ // Find the total number of cameras available
315
+ numberOfCameras = Camera.getNumberOfCameras();
316
+
317
+ int facing = "front".equals(defaultCamera) ? Camera.CameraInfo.CAMERA_FACING_FRONT : Camera.CameraInfo.CAMERA_FACING_BACK;
318
+
319
+ // Find the ID of the default camera
320
+ Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
321
+ for (int i = 0; i < numberOfCameras; i++) {
322
+ Camera.getCameraInfo(i, cameraInfo);
323
+ if (cameraInfo.facing == facing) {
324
+ defaultCameraId = i;
325
+ break;
326
+ }
327
+ }
328
+ }
329
+
330
+ @Override
331
+ public void onResume() {
332
+ super.onResume();
333
+
334
+ mCamera = Camera.open(defaultCameraId);
335
+
336
+ if (cameraParameters != null) {
337
+ mCamera.setParameters(cameraParameters);
338
+ }
339
+
340
+ cameraCurrentlyLocked = defaultCameraId;
341
+
342
+ if (mPreview.mPreviewSize == null) {
343
+ mPreview.setCamera(mCamera, cameraCurrentlyLocked);
344
+ eventListener.onCameraStarted();
345
+ } else {
346
+ mPreview.switchCamera(mCamera, cameraCurrentlyLocked);
347
+ mCamera.startPreview();
348
+ }
349
+
350
+ Log.d(TAG, "cameraCurrentlyLocked:" + cameraCurrentlyLocked);
351
+
352
+ final FrameLayout frameContainerLayout = (FrameLayout) view.findViewById(
353
+ getResources().getIdentifier("frame_container", "id", appResourcesPackage)
354
+ );
355
+
356
+ ViewTreeObserver viewTreeObserver = frameContainerLayout.getViewTreeObserver();
357
+
358
+ if (viewTreeObserver.isAlive()) {
359
+ viewTreeObserver.addOnGlobalLayoutListener(
360
+ new ViewTreeObserver.OnGlobalLayoutListener() {
361
+ @Override
362
+ public void onGlobalLayout() {
363
+ frameContainerLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
364
+ frameContainerLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
365
+ Activity activity = getActivity();
366
+ if (isAdded() && activity != null) {
367
+ final RelativeLayout frameCamContainerLayout = (RelativeLayout) view.findViewById(
368
+ getResources().getIdentifier("frame_camera_cont", "id", appResourcesPackage)
369
+ );
370
+
371
+ FrameLayout.LayoutParams camViewLayout = new FrameLayout.LayoutParams(
372
+ frameContainerLayout.getWidth(),
373
+ frameContainerLayout.getHeight()
374
+ );
375
+ camViewLayout.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
376
+ frameCamContainerLayout.setLayoutParams(camViewLayout);
377
+ }
378
+ }
379
+ }
380
+ );
381
+ }
382
+ }
383
+
384
+ @Override
385
+ public void onPause() {
386
+ super.onPause();
387
+
388
+ // Because the Camera object is a shared resource, it's very important to release it when the activity is paused.
389
+ if (mCamera != null) {
390
+ setDefaultCameraId();
391
+ mPreview.setCamera(null, -1);
392
+ mCamera.setPreviewCallback(null);
393
+ mCamera.release();
394
+ mCamera = null;
395
+ }
396
+ }
397
+
398
+ @Override
399
+ public void onConfigurationChanged(Configuration newConfig) {
400
+ super.onConfigurationChanged(newConfig);
401
+
402
+ final FrameLayout frameContainerLayout = (FrameLayout) view.findViewById(
403
+ getResources().getIdentifier("frame_container", "id", appResourcesPackage)
404
+ );
405
+
406
+ final int previousOrientation = frameContainerLayout.getHeight() > frameContainerLayout.getWidth()
407
+ ? Configuration.ORIENTATION_PORTRAIT
408
+ : Configuration.ORIENTATION_LANDSCAPE;
409
+ // Checks if the orientation of the screen has changed
410
+ if (newConfig.orientation != previousOrientation) {
411
+ final RelativeLayout frameCamContainerLayout = (RelativeLayout) view.findViewById(
412
+ getResources().getIdentifier("frame_camera_cont", "id", appResourcesPackage)
413
+ );
414
+
415
+ frameContainerLayout.getLayoutParams().width = frameCamContainerLayout.getHeight();
416
+ frameContainerLayout.getLayoutParams().height = frameCamContainerLayout.getWidth();
417
+
418
+ frameCamContainerLayout.getLayoutParams().width = frameCamContainerLayout.getHeight();
419
+ frameCamContainerLayout.getLayoutParams().height = frameCamContainerLayout.getWidth();
420
+
421
+ frameContainerLayout.invalidate();
422
+ frameContainerLayout.requestLayout();
423
+
424
+ frameCamContainerLayout.forceLayout();
425
+
426
+ mPreview.setCameraDisplayOrientation();
427
+ }
428
+ }
429
+
430
+ public Camera getCamera() {
431
+ return mCamera;
432
+ }
433
+
434
+ public void switchCamera() {
435
+ // check for availability of multiple cameras
436
+ if (numberOfCameras == 1) {
437
+ //There is only one camera available
438
+ } else {
439
+ Log.d(TAG, "numberOfCameras: " + numberOfCameras);
440
+
441
+ // OK, we have multiple cameras. Release this camera -> cameraCurrentlyLocked
442
+ if (mCamera != null) {
443
+ mCamera.stopPreview();
444
+ mPreview.setCamera(null, -1);
445
+ mCamera.release();
446
+ mCamera = null;
447
+ }
448
+
449
+ Log.d(TAG, "cameraCurrentlyLocked := " + Integer.toString(cameraCurrentlyLocked));
450
+ try {
451
+ cameraCurrentlyLocked = (cameraCurrentlyLocked + 1) % numberOfCameras;
452
+ Log.d(TAG, "cameraCurrentlyLocked new: " + cameraCurrentlyLocked);
453
+ } catch (Exception exception) {
454
+ Log.d(TAG, exception.getMessage());
455
+ }
456
+
457
+ // Acquire the next camera and request Preview to reconfigure parameters.
458
+ mCamera = Camera.open(cameraCurrentlyLocked);
459
+
460
+ if (cameraParameters != null) {
461
+ Log.d(TAG, "camera parameter not null");
462
+
463
+ // Check for flashMode as well to prevent error on frontward facing camera.
464
+ List<String> supportedFlashModesNewCamera = mCamera.getParameters().getSupportedFlashModes();
465
+ String currentFlashModePreviousCamera = cameraParameters.getFlashMode();
466
+ if (supportedFlashModesNewCamera != null && supportedFlashModesNewCamera.contains(currentFlashModePreviousCamera)) {
467
+ Log.d(TAG, "current flash mode supported on new camera. setting params");
468
+ /* mCamera.setParameters(cameraParameters);
469
+ The line above is disabled because parameters that can actually be changed are different from one device to another. Makes less sense trying to reconfigure them when changing camera device while those settings gan be changed using plugin methods.
470
+ */
471
+ } else {
472
+ Log.d(TAG, "current flash mode NOT supported on new camera");
473
+ }
474
+ } else {
475
+ Log.d(TAG, "camera parameter NULL");
476
+ }
477
+
478
+ mPreview.switchCamera(mCamera, cameraCurrentlyLocked);
479
+
480
+ mCamera.startPreview();
481
+ }
482
+ }
483
+
484
+ public void setCameraParameters(Camera.Parameters params) {
485
+ cameraParameters = params;
486
+
487
+ if (mCamera != null && cameraParameters != null) {
488
+ mCamera.setParameters(cameraParameters);
489
+ }
490
+ }
491
+
492
+ public boolean hasFrontCamera() {
493
+ return getActivity().getApplicationContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
494
+ }
495
+
496
+ public static Bitmap applyMatrix(Bitmap source, Matrix matrix) {
497
+ return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
498
+ }
499
+
500
+ ShutterCallback shutterCallback = new ShutterCallback() {
501
+ public void onShutter() {
502
+ // do nothing, availabilty of this callback causes default system shutter sound to work
503
+ }
504
+ };
505
+
506
+ private static int exifToDegrees(int exifOrientation) {
507
+ if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) {
508
+ return 90;
509
+ } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {
510
+ return 180;
511
+ } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
512
+ return 270;
513
+ }
514
+ return 0;
515
+ }
516
+
517
+ private String getTempDirectoryPath() {
518
+ File cache = null;
519
+
520
+ // Use internal storage
521
+ cache = getActivity().getCacheDir();
522
+
523
+ // Create the cache directory if it doesn't exist
524
+ cache.mkdirs();
525
+ return cache.getAbsolutePath();
526
+ }
527
+
528
+ private String getTempFilePath() {
529
+ return getTempDirectoryPath() + "/cpcp_capture_" + UUID.randomUUID().toString().replace("-", "").substring(0, 8) + ".jpg";
530
+ }
531
+
532
+ PictureCallback jpegPictureCallback = new PictureCallback() {
533
+ public void onPictureTaken(byte[] data, Camera arg1) {
534
+ Log.d(TAG, "CameraPreview jpegPictureCallback");
535
+
536
+ try {
537
+ if (!disableExifHeaderStripping) {
538
+ Matrix matrix = new Matrix();
539
+ if (cameraCurrentlyLocked == Camera.CameraInfo.CAMERA_FACING_FRONT) {
540
+ matrix.preScale(1.0f, -1.0f);
541
+ }
542
+
543
+ ExifInterface exifInterface = new ExifInterface(new ByteArrayInputStream(data));
544
+ int rotation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
545
+ int rotationInDegrees = exifToDegrees(rotation);
546
+
547
+ if (rotation != 0f) {
548
+ matrix.preRotate(rotationInDegrees);
549
+ }
550
+
551
+ // Check if matrix has changed. In that case, apply matrix and override data
552
+ if (!matrix.isIdentity()) {
553
+ Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
554
+ bitmap = applyMatrix(bitmap, matrix);
555
+
556
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
557
+ bitmap.compress(CompressFormat.JPEG, currentQuality, outputStream);
558
+ data = outputStream.toByteArray();
559
+ }
560
+ }
561
+
562
+ if (!storeToFile) {
563
+ String encodedImage = Base64.encodeToString(data, Base64.NO_WRAP);
564
+
565
+ eventListener.onPictureTaken(encodedImage);
566
+ } else {
567
+ String path = getTempFilePath();
568
+ FileOutputStream out = new FileOutputStream(path);
569
+ out.write(data);
570
+ out.close();
571
+ eventListener.onPictureTaken(path);
572
+ }
573
+ Log.d(TAG, "CameraPreview pictureTakenHandler called back");
574
+ } catch (OutOfMemoryError e) {
575
+ // most likely failed to allocate memory for rotateBitmap
576
+ Log.d(TAG, "CameraPreview OutOfMemoryError");
577
+ // failed to allocate memory
578
+ eventListener.onPictureTakenError("Picture too large (memory)");
579
+ } catch (IOException e) {
580
+ Log.d(TAG, "CameraPreview IOException");
581
+ eventListener.onPictureTakenError("IO Error when extracting exif");
582
+ } catch (Exception e) {
583
+ Log.d(TAG, "CameraPreview onPictureTaken general exception");
584
+ } finally {
585
+ canTakePicture = true;
586
+ mCamera.startPreview();
587
+ }
588
+ }
589
+ };
590
+
591
+ private Camera.Size getOptimalPictureSize(
592
+ final int width,
593
+ final int height,
594
+ final Camera.Size previewSize,
595
+ final List<Camera.Size> supportedSizes
596
+ ) {
597
+ /*
598
+ get the supportedPictureSize that:
599
+ - matches exactly width and height
600
+ - has the closest aspect ratio to the preview aspect ratio
601
+ - has picture.width and picture.height closest to width and height
602
+ - has the highest supported picture width and height up to 2 Megapixel if width == 0 || height == 0
603
+ */
604
+ Camera.Size size = mCamera.new Size(width, height);
605
+
606
+ // convert to landscape if necessary
607
+ if (size.width < size.height) {
608
+ int temp = size.width;
609
+ size.width = size.height;
610
+ size.height = temp;
611
+ }
612
+
613
+ Camera.Size requestedSize = mCamera.new Size(size.width, size.height);
614
+
615
+ double previewAspectRatio = (double) previewSize.width / (double) previewSize.height;
616
+
617
+ if (previewAspectRatio < 1.0) {
618
+ // reset ratio to landscape
619
+ previewAspectRatio = 1.0 / previewAspectRatio;
620
+ }
621
+
622
+ Log.d(TAG, "CameraPreview previewAspectRatio " + previewAspectRatio);
623
+
624
+ double aspectTolerance = 0.1;
625
+ double bestDifference = Double.MAX_VALUE;
626
+
627
+ for (int i = 0; i < supportedSizes.size(); i++) {
628
+ Camera.Size supportedSize = supportedSizes.get(i);
629
+
630
+ // Perfect match
631
+ if (supportedSize.equals(requestedSize)) {
632
+ Log.d(TAG, "CameraPreview optimalPictureSize " + supportedSize.width + 'x' + supportedSize.height);
633
+ return supportedSize;
634
+ }
635
+
636
+ double difference = Math.abs(previewAspectRatio - ((double) supportedSize.width / (double) supportedSize.height));
637
+
638
+ if (difference < bestDifference - aspectTolerance) {
639
+ // better aspectRatio found
640
+ if ((width != 0 && height != 0) || (supportedSize.width * supportedSize.height < 2048 * 1024)) {
641
+ size.width = supportedSize.width;
642
+ size.height = supportedSize.height;
643
+ bestDifference = difference;
644
+ }
645
+ } else if (difference < bestDifference + aspectTolerance) {
646
+ // same aspectRatio found (within tolerance)
647
+ if (width == 0 || height == 0) {
648
+ // set highest supported resolution below 2 Megapixel
649
+ if ((size.width < supportedSize.width) && (supportedSize.width * supportedSize.height < 2048 * 1024)) {
650
+ size.width = supportedSize.width;
651
+ size.height = supportedSize.height;
652
+ }
653
+ } else {
654
+ // check if this pictureSize closer to requested width and height
655
+ if (
656
+ Math.abs(width * height - supportedSize.width * supportedSize.height) <
657
+ Math.abs(width * height - size.width * size.height)
658
+ ) {
659
+ size.width = supportedSize.width;
660
+ size.height = supportedSize.height;
661
+ }
662
+ }
663
+ }
664
+ }
665
+ Log.d(TAG, "CameraPreview optimalPictureSize " + size.width + 'x' + size.height);
666
+ return size;
667
+ }
668
+
669
+ static byte[] rotateNV21(final byte[] yuv, final int width, final int height, final int rotation) {
670
+ if (rotation == 0) return yuv;
671
+ if (rotation % 90 != 0 || rotation < 0 || rotation > 270) {
672
+ throw new IllegalArgumentException("0 <= rotation < 360, rotation % 90 == 0");
673
+ }
674
+
675
+ final byte[] output = new byte[yuv.length];
676
+ final int frameSize = width * height;
677
+ final boolean swap = rotation % 180 != 0;
678
+ final boolean xflip = rotation % 270 != 0;
679
+ final boolean yflip = rotation >= 180;
680
+
681
+ for (int j = 0; j < height; j++) {
682
+ for (int i = 0; i < width; i++) {
683
+ final int yIn = j * width + i;
684
+ final int uIn = frameSize + (j >> 1) * width + (i & ~1);
685
+ final int vIn = uIn + 1;
686
+
687
+ final int wOut = swap ? height : width;
688
+ final int hOut = swap ? width : height;
689
+ final int iSwapped = swap ? j : i;
690
+ final int jSwapped = swap ? i : j;
691
+ final int iOut = xflip ? wOut - iSwapped - 1 : iSwapped;
692
+ final int jOut = yflip ? hOut - jSwapped - 1 : jSwapped;
693
+
694
+ final int yOut = jOut * wOut + iOut;
695
+ final int uOut = frameSize + (jOut >> 1) * wOut + (iOut & ~1);
696
+ final int vOut = uOut + 1;
697
+
698
+ output[yOut] = (byte) (0xff & yuv[yIn]);
699
+ output[uOut] = (byte) (0xff & yuv[uIn]);
700
+ output[vOut] = (byte) (0xff & yuv[vIn]);
701
+ }
702
+ }
703
+ return output;
704
+ }
705
+
706
+ public void setOpacity(final float opacity) {
707
+ Log.d(TAG, "set opacity:" + opacity);
708
+ this.opacity = opacity;
709
+ mPreview.setOpacity(opacity);
710
+ }
711
+
712
+ public void takeSnapshot(final int quality) {
713
+ mCamera.setPreviewCallback(
714
+ new Camera.PreviewCallback() {
715
+ @Override
716
+ public void onPreviewFrame(byte[] bytes, Camera camera) {
717
+ try {
718
+ Camera.Parameters parameters = camera.getParameters();
719
+ Camera.Size size = parameters.getPreviewSize();
720
+ int orientation = mPreview.getDisplayOrientation();
721
+ if (mPreview.getCameraFacing() == Camera.CameraInfo.CAMERA_FACING_FRONT) {
722
+ bytes = rotateNV21(bytes, size.width, size.height, (360 - orientation) % 360);
723
+ } else {
724
+ bytes = rotateNV21(bytes, size.width, size.height, orientation);
725
+ }
726
+ // switch width/height when rotating 90/270 deg
727
+ Rect rect = orientation == 90 || orientation == 270
728
+ ? new Rect(0, 0, size.height, size.width)
729
+ : new Rect(0, 0, size.width, size.height);
730
+ YuvImage yuvImage = new YuvImage(bytes, parameters.getPreviewFormat(), rect.width(), rect.height(), null);
731
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
732
+ yuvImage.compressToJpeg(rect, quality, byteArrayOutputStream);
733
+ byte[] data = byteArrayOutputStream.toByteArray();
734
+ byteArrayOutputStream.close();
735
+ eventListener.onSnapshotTaken(Base64.encodeToString(data, Base64.NO_WRAP));
736
+ } catch (IOException e) {
737
+ Log.d(TAG, "CameraPreview IOException");
738
+ eventListener.onSnapshotTakenError("IO Error");
739
+ } finally {
740
+ mCamera.setPreviewCallback(null);
741
+ }
742
+ }
743
+ }
744
+ );
745
+ }
746
+
747
+ public void takePicture(final int width, final int height, final int quality) {
748
+ Log.d(TAG, "CameraPreview takePicture width: " + width + ", height: " + height + ", quality: " + quality);
749
+
750
+ if (mPreview != null) {
751
+ if (!canTakePicture) {
752
+ return;
753
+ }
754
+
755
+ canTakePicture = false;
756
+
757
+ new Thread() {
758
+ public void run() {
759
+ Camera.Parameters params = mCamera.getParameters();
760
+
761
+ Camera.Size size = getOptimalPictureSize(width, height, params.getPreviewSize(), params.getSupportedPictureSizes());
762
+ params.setPictureSize(size.width, size.height);
763
+ currentQuality = quality;
764
+
765
+ if (cameraCurrentlyLocked == Camera.CameraInfo.CAMERA_FACING_FRONT && !storeToFile) {
766
+ // The image will be recompressed in the callback
767
+ params.setJpegQuality(99);
768
+ } else {
769
+ params.setJpegQuality(quality);
770
+ }
771
+
772
+ if (cameraCurrentlyLocked == Camera.CameraInfo.CAMERA_FACING_FRONT && disableExifHeaderStripping) {
773
+ Activity activity = getActivity();
774
+ int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
775
+ int degrees = 0;
776
+ switch (rotation) {
777
+ case Surface.ROTATION_0:
778
+ degrees = 0;
779
+ break;
780
+ case Surface.ROTATION_90:
781
+ degrees = 180;
782
+ break;
783
+ case Surface.ROTATION_180:
784
+ degrees = 270;
785
+ break;
786
+ case Surface.ROTATION_270:
787
+ degrees = 0;
788
+ break;
789
+ }
790
+ int orientation;
791
+ Camera.CameraInfo info = new Camera.CameraInfo();
792
+ if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
793
+ orientation = (info.orientation + degrees) % 360;
794
+ if (degrees != 0) {
795
+ orientation = (360 - orientation) % 360;
796
+ }
797
+ } else {
798
+ orientation = (info.orientation - degrees + 360) % 360;
799
+ }
800
+ params.setRotation(orientation);
801
+ } else {
802
+ params.setRotation(mPreview.getDisplayOrientation());
803
+ }
804
+
805
+ mCamera.setParameters(params);
806
+ mCamera.takePicture(shutterCallback, null, jpegPictureCallback);
807
+ }
808
+ }
809
+ .start();
810
+ } else {
811
+ canTakePicture = true;
812
+ }
813
+ }
814
+
815
+ public void startRecord(
816
+ final String filePath,
817
+ final String camera,
818
+ final int width,
819
+ final int height,
820
+ final int quality,
821
+ final boolean withFlash,
822
+ final int maxDuration,
823
+ final String lens
824
+ ) {
825
+ Log.d(TAG, "CameraPreview startRecord camera: " + camera + " width: " + width + ", height: " + height + ", quality: " + quality + ", lens: " + lens);
826
+ Activity activity = getActivity();
827
+ muteStream(true, activity);
828
+ if (this.mRecordingState == RecordingState.STARTED) {
829
+ Log.d(TAG, "Already Recording");
830
+ return;
831
+ }
832
+
833
+ this.recordFilePath = filePath;
834
+ int mOrientationHint = calculateOrientationHint();
835
+ int videoWidth = 0; //set whatever
836
+ int videoHeight = 0; //set whatever
837
+
838
+ Camera.Parameters cameraParams = mCamera.getParameters();
839
+ if (withFlash) {
840
+ cameraParams.setFlashMode(withFlash ? Camera.Parameters.FLASH_MODE_TORCH : Camera.Parameters.FLASH_MODE_OFF);
841
+ mCamera.setParameters(cameraParams);
842
+ mCamera.startPreview();
843
+ }
844
+
845
+ mCamera.unlock();
846
+ mRecorder = new MediaRecorder();
847
+
848
+ try {
849
+ mRecorder.setCamera(mCamera);
850
+
851
+ CamcorderProfile profile;
852
+ if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_HIGH)) {
853
+ profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_HIGH);
854
+ } else {
855
+ if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_480P)) {
856
+ profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_480P);
857
+ } else {
858
+ if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_720P)) {
859
+ profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_720P);
860
+ } else {
861
+ if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_1080P)) {
862
+ profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_1080P);
863
+ } else {
864
+ profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_LOW);
865
+ }
866
+ }
867
+ }
868
+ }
869
+
870
+ mRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_RECOGNITION);
871
+ mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
872
+ mRecorder.setProfile(profile);
873
+ mRecorder.setOutputFile(filePath);
874
+ mRecorder.setOrientationHint(mOrientationHint);
875
+ mRecorder.setMaxDuration(maxDuration);
876
+
877
+ mRecorder.prepare();
878
+ Log.d(TAG, "Starting recording");
879
+ mRecorder.start();
880
+ eventListener.onStartRecordVideo();
881
+ } catch (IOException e) {
882
+ eventListener.onStartRecordVideoError(e.getMessage());
883
+ }
884
+ }
885
+
886
+ public int calculateOrientationHint() {
887
+ DisplayMetrics dm = new DisplayMetrics();
888
+ Camera.CameraInfo info = new Camera.CameraInfo();
889
+ Camera.getCameraInfo(defaultCameraId, info);
890
+ int cameraRotationOffset = info.orientation;
891
+ Activity activity = getActivity();
892
+
893
+ activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
894
+ int currentScreenRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
895
+
896
+ int degrees = 0;
897
+ switch (currentScreenRotation) {
898
+ case Surface.ROTATION_0:
899
+ degrees = 0;
900
+ break;
901
+ case Surface.ROTATION_90:
902
+ degrees = 90;
903
+ break;
904
+ case Surface.ROTATION_180:
905
+ degrees = 180;
906
+ break;
907
+ case Surface.ROTATION_270:
908
+ degrees = 270;
909
+ break;
910
+ }
911
+
912
+ int orientation;
913
+ if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
914
+ orientation = (cameraRotationOffset + degrees) % 360;
915
+ if (degrees != 0) {
916
+ orientation = (360 - orientation) % 360;
917
+ }
918
+ } else {
919
+ orientation = (cameraRotationOffset - degrees + 360) % 360;
920
+ }
921
+ Log.w(TAG, "************orientationHint ***********= " + orientation);
922
+
923
+ return orientation;
924
+ }
925
+
926
+ public void stopRecord() {
927
+ Log.d(TAG, "stopRecord");
928
+
929
+ try {
930
+ mRecorder.stop();
931
+ mRecorder.reset(); // clear recorder configuration
932
+ mRecorder.release(); // release the recorder object
933
+ mRecorder = null;
934
+ mCamera.lock();
935
+ Camera.Parameters cameraParams = mCamera.getParameters();
936
+ cameraParams.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
937
+ mCamera.setParameters(cameraParams);
938
+ mCamera.startPreview();
939
+ eventListener.onStopRecordVideo(this.recordFilePath);
940
+ } catch (Exception e) {
941
+ eventListener.onStopRecordVideoError(e.getMessage());
942
+ }
943
+ }
944
+
945
+ public void muteStream(boolean mute, Activity activity) {
946
+ AudioManager audioManager = ((AudioManager) activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE));
947
+ int direction = mute ? audioManager.ADJUST_MUTE : audioManager.ADJUST_UNMUTE;
948
+ }
949
+
950
+ public void setFocusArea(final int pointX, final int pointY, final Camera.AutoFocusCallback callback) {
951
+ if (mCamera != null) {
952
+ mCamera.cancelAutoFocus();
953
+
954
+ Camera.Parameters parameters = mCamera.getParameters();
955
+
956
+ Rect focusRect = calculateTapArea(pointX, pointY, 1f);
957
+ parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
958
+ parameters.setFocusAreas(Arrays.asList(new Camera.Area(focusRect, 1000)));
959
+
960
+ if (parameters.getMaxNumMeteringAreas() > 0) {
961
+ Rect meteringRect = calculateTapArea(pointX, pointY, 1.5f);
962
+ parameters.setMeteringAreas(Arrays.asList(new Camera.Area(meteringRect, 1000)));
963
+ }
964
+
965
+ try {
966
+ setCameraParameters(parameters);
967
+ mCamera.autoFocus(callback);
968
+ } catch (Exception e) {
969
+ Log.d(TAG, e.getMessage());
970
+ callback.onAutoFocus(false, this.mCamera);
971
+ }
972
+ }
973
+ }
974
+
975
+ private Rect calculateTapArea(float x, float y, float coefficient) {
976
+ if (x < 100) {
977
+ x = 100;
978
+ }
979
+ if (x > width - 100) {
980
+ x = width - 100;
981
+ }
982
+ if (y < 100) {
983
+ y = 100;
984
+ }
985
+ if (y > height - 100) {
986
+ y = height - 100;
987
+ }
988
+ return new Rect(
989
+ Math.round((x - 100) * 2000 / width - 1000),
990
+ Math.round((y - 100) * 2000 / height - 1000),
991
+ Math.round((x + 100) * 2000 / width - 1000),
992
+ Math.round((y + 100) * 2000 / height - 1000)
993
+ );
994
+ }
995
+
996
+ /**
997
+ * Determine the space between the first two fingers
998
+ */
999
+ private static float getFingerSpacing(MotionEvent event) {
1000
+ // ...
1001
+ float x = event.getX(0) - event.getX(1);
1002
+ float y = event.getY(0) - event.getY(1);
1003
+ return (float) Math.sqrt(x * x + y * y);
1004
+ }
1005
+ }