@capgo/camera-preview 3.6.23 → 4.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 (42) hide show
  1. package/README.md +67 -405
  2. package/android/build.gradle +8 -7
  3. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  4. package/android/gradle/wrapper/gradle-wrapper.properties +1 -1
  5. package/android/gradle.properties +1 -1
  6. package/android/gradlew +2 -2
  7. package/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java +6 -6
  8. package/android/src/main/AndroidManifest.xml +1 -1
  9. package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java +1105 -854
  10. package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +543 -428
  11. package/android/src/main/java/com/ahm/capacitor/camera/preview/CustomSurfaceView.java +15 -10
  12. package/android/src/main/java/com/ahm/capacitor/camera/preview/CustomTextureView.java +31 -21
  13. package/android/src/main/java/com/ahm/capacitor/camera/preview/Preview.java +386 -332
  14. package/android/src/main/java/com/ahm/capacitor/camera/preview/TapGestureDetector.java +13 -13
  15. package/android/src/test/java/com/getcapacitor/ExampleUnitTest.java +4 -4
  16. package/dist/docs.json +208 -37
  17. package/dist/esm/definitions.d.ts +76 -3
  18. package/dist/esm/index.d.ts +2 -2
  19. package/dist/esm/index.js +4 -4
  20. package/dist/esm/web.d.ts +2 -2
  21. package/dist/esm/web.js +39 -36
  22. package/dist/esm/web.js.map +1 -1
  23. package/dist/plugin.cjs.js +39 -36
  24. package/dist/plugin.cjs.js.map +1 -1
  25. package/dist/plugin.js +39 -36
  26. package/dist/plugin.js.map +1 -1
  27. package/ios/Plugin/CameraController.swift +1 -1
  28. package/ios/Plugin/Plugin.swift +1 -1
  29. package/ios/Podfile.lock +3 -3
  30. package/package.json +22 -22
  31. package/android/.gradle/7.6/checksums/checksums.lock +0 -0
  32. package/android/.gradle/7.6/checksums/md5-checksums.bin +0 -0
  33. package/android/.gradle/7.6/checksums/sha1-checksums.bin +0 -0
  34. package/android/.gradle/7.6/dependencies-accessors/dependencies-accessors.lock +0 -0
  35. package/android/.gradle/7.6/dependencies-accessors/gc.properties +0 -0
  36. package/android/.gradle/7.6/executionHistory/executionHistory.lock +0 -0
  37. package/android/.gradle/7.6/fileChanges/last-build.bin +0 -0
  38. package/android/.gradle/7.6/fileHashes/fileHashes.lock +0 -0
  39. package/android/.gradle/7.6/gc.properties +0 -0
  40. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  41. package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  42. package/android/.gradle/vcs-1/gc.properties +0 -0
@@ -28,488 +28,603 @@ import java.io.File;
28
28
  import java.util.List;
29
29
  import org.json.JSONArray;
30
30
 
31
- @CapacitorPlugin(name = "CameraPreview", permissions = { @Permission(strings = { CAMERA }, alias = CameraPreview.CAMERA_PERMISSION_ALIAS) })
32
- public class CameraPreview extends Plugin implements CameraActivity.CameraPreviewListener {
33
-
34
- static final String CAMERA_PERMISSION_ALIAS = "camera";
35
-
36
- private static String VIDEO_FILE_PATH = "";
37
- private static String VIDEO_FILE_EXTENSION = ".mp4";
38
-
39
- private String captureCallbackId = "";
40
- private String snapshotCallbackId = "";
41
- private String recordCallbackId = "";
42
- private String cameraStartCallbackId = "";
43
-
44
- // keep track of previously specified orientation to support locking orientation:
45
- private int previousOrientationRequest = -1;
46
-
47
- private CameraActivity fragment;
48
- private int containerViewId = 20;
49
-
50
- @PluginMethod
51
- public void start(PluginCall call) {
52
- if (PermissionState.GRANTED.equals(getPermissionState(CAMERA_PERMISSION_ALIAS))) {
53
- startCamera(call);
54
- } else {
55
- requestPermissionForAlias(CAMERA_PERMISSION_ALIAS, call, "handleCameraPermissionResult");
56
- }
31
+ @CapacitorPlugin(
32
+ name = "CameraPreview",
33
+ permissions = {
34
+ @Permission(
35
+ strings = { CAMERA },
36
+ alias = CameraPreview.CAMERA_PERMISSION_ALIAS
37
+ ),
38
+ }
39
+ )
40
+ public class CameraPreview
41
+ extends Plugin
42
+ implements CameraActivity.CameraPreviewListener {
43
+
44
+ static final String CAMERA_PERMISSION_ALIAS = "camera";
45
+
46
+ private static String VIDEO_FILE_PATH = "";
47
+ private static String VIDEO_FILE_EXTENSION = ".mp4";
48
+
49
+ private String captureCallbackId = "";
50
+ private String snapshotCallbackId = "";
51
+ private String recordCallbackId = "";
52
+ private String cameraStartCallbackId = "";
53
+
54
+ // keep track of previously specified orientation to support locking orientation:
55
+ private int previousOrientationRequest = -1;
56
+
57
+ private CameraActivity fragment;
58
+ private int containerViewId = 20;
59
+
60
+ @PluginMethod
61
+ public void start(PluginCall call) {
62
+ if (
63
+ PermissionState.GRANTED.equals(
64
+ getPermissionState(CAMERA_PERMISSION_ALIAS)
65
+ )
66
+ ) {
67
+ startCamera(call);
68
+ } else {
69
+ requestPermissionForAlias(
70
+ CAMERA_PERMISSION_ALIAS,
71
+ call,
72
+ "handleCameraPermissionResult"
73
+ );
57
74
  }
58
-
59
- @PluginMethod
60
- public void flip(PluginCall call) {
61
- try {
62
- fragment.switchCamera();
63
- call.resolve();
64
- } catch (Exception e) {
65
- Logger.debug(getLogTag(), "Camera flip exception: " + e);
66
- call.reject("failed to flip camera");
67
- }
75
+ }
76
+
77
+ @PluginMethod
78
+ public void flip(PluginCall call) {
79
+ try {
80
+ fragment.switchCamera();
81
+ call.resolve();
82
+ } catch (Exception e) {
83
+ Logger.debug(getLogTag(), "Camera flip exception: " + e);
84
+ call.reject("failed to flip camera");
68
85
  }
86
+ }
69
87
 
70
- @PluginMethod
71
- public void setOpacity(PluginCall call) {
72
- if (this.hasCamera(call) == false) {
73
- call.error("Camera is not running");
74
- return;
75
- }
76
-
77
- bridge.saveCall(call);
78
- Float opacity = call.getFloat("opacity", 1F);
79
- fragment.setOpacity(opacity);
88
+ @PluginMethod
89
+ public void setOpacity(PluginCall call) {
90
+ if (this.hasCamera(call) == false) {
91
+ call.error("Camera is not running");
92
+ return;
80
93
  }
81
94
 
82
- @PluginMethod
83
- public void capture(PluginCall call) {
84
- if (this.hasCamera(call) == false) {
85
- call.reject("Camera is not running");
86
- return;
87
- }
88
- bridge.saveCall(call);
89
- captureCallbackId = call.getCallbackId();
90
-
91
- Integer quality = call.getInt("quality", 85);
92
- // Image Dimensions - Optional
93
- Integer width = call.getInt("width", 0);
94
- Integer height = call.getInt("height", 0);
95
- fragment.takePicture(width, height, quality);
96
- }
97
-
98
- @PluginMethod
99
- public void captureSample(PluginCall call) {
100
- if (this.hasCamera(call) == false) {
101
- call.reject("Camera is not running");
102
- return;
103
- }
104
- bridge.saveCall(call);
105
- snapshotCallbackId = call.getCallbackId();
95
+ bridge.saveCall(call);
96
+ Float opacity = call.getFloat("opacity", 1F);
97
+ fragment.setOpacity(opacity);
98
+ }
106
99
 
107
- Integer quality = call.getInt("quality", 85);
108
- fragment.takeSnapshot(quality);
100
+ @PluginMethod
101
+ public void capture(PluginCall call) {
102
+ if (this.hasCamera(call) == false) {
103
+ call.reject("Camera is not running");
104
+ return;
109
105
  }
110
-
111
- @PluginMethod
112
- public void stop(final PluginCall call) {
113
- bridge
114
- .getActivity()
115
- .runOnUiThread(
116
- new Runnable() {
117
- @Override
118
- public void run() {
119
- FrameLayout containerView = getBridge().getActivity().findViewById(containerViewId);
120
-
121
- // allow orientation changes after closing camera:
122
- getBridge().getActivity().setRequestedOrientation(previousOrientationRequest);
123
-
124
- if (containerView != null) {
125
- ((ViewGroup) getBridge().getWebView().getParent()).removeView(containerView);
126
- getBridge().getWebView().setBackgroundColor(Color.WHITE);
127
- FragmentManager fragmentManager = getActivity().getFragmentManager();
128
- FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
129
- fragmentTransaction.remove(fragment);
130
- fragmentTransaction.commit();
131
- fragment = null;
132
-
133
- call.resolve();
134
- } else {
135
- call.reject("camera already stopped");
136
- }
137
- }
138
- }
139
- );
106
+ bridge.saveCall(call);
107
+ captureCallbackId = call.getCallbackId();
108
+
109
+ Integer quality = call.getInt("quality", 85);
110
+ // Image Dimensions - Optional
111
+ Integer width = call.getInt("width", 0);
112
+ Integer height = call.getInt("height", 0);
113
+ fragment.takePicture(width, height, quality);
114
+ }
115
+
116
+ @PluginMethod
117
+ public void captureSample(PluginCall call) {
118
+ if (this.hasCamera(call) == false) {
119
+ call.reject("Camera is not running");
120
+ return;
140
121
  }
141
-
142
- @PluginMethod
143
- public void getSupportedFlashModes(PluginCall call) {
144
- if (this.hasCamera(call) == false) {
145
- call.reject("Camera is not running");
146
- return;
147
- }
148
-
149
- Camera camera = fragment.getCamera();
150
- Camera.Parameters params = camera.getParameters();
151
- List<String> supportedFlashModes;
152
- supportedFlashModes = params.getSupportedFlashModes();
153
- JSONArray jsonFlashModes = new JSONArray();
154
-
155
- if (supportedFlashModes != null) {
156
- for (int i = 0; i < supportedFlashModes.size(); i++) {
157
- jsonFlashModes.put(new String(supportedFlashModes.get(i)));
122
+ bridge.saveCall(call);
123
+ snapshotCallbackId = call.getCallbackId();
124
+
125
+ Integer quality = call.getInt("quality", 85);
126
+ fragment.takeSnapshot(quality);
127
+ }
128
+
129
+ @PluginMethod
130
+ public void stop(final PluginCall call) {
131
+ bridge
132
+ .getActivity()
133
+ .runOnUiThread(
134
+ new Runnable() {
135
+ @Override
136
+ public void run() {
137
+ FrameLayout containerView = getBridge()
138
+ .getActivity()
139
+ .findViewById(containerViewId);
140
+
141
+ // allow orientation changes after closing camera:
142
+ getBridge()
143
+ .getActivity()
144
+ .setRequestedOrientation(previousOrientationRequest);
145
+
146
+ if (containerView != null) {
147
+ ((ViewGroup) getBridge().getWebView().getParent()).removeView(
148
+ containerView
149
+ );
150
+ getBridge().getWebView().setBackgroundColor(Color.WHITE);
151
+ FragmentManager fragmentManager = getActivity()
152
+ .getFragmentManager();
153
+ FragmentTransaction fragmentTransaction =
154
+ fragmentManager.beginTransaction();
155
+ fragmentTransaction.remove(fragment);
156
+ fragmentTransaction.commit();
157
+ fragment = null;
158
+
159
+ call.resolve();
160
+ } else {
161
+ call.reject("camera already stopped");
158
162
  }
163
+ }
159
164
  }
160
-
161
- JSObject jsObject = new JSObject();
162
- jsObject.put("result", jsonFlashModes);
163
- call.resolve(jsObject);
165
+ );
166
+ }
167
+
168
+ @PluginMethod
169
+ public void getSupportedFlashModes(PluginCall call) {
170
+ if (this.hasCamera(call) == false) {
171
+ call.reject("Camera is not running");
172
+ return;
164
173
  }
165
174
 
166
- @PluginMethod
167
- public void getHorizontalFov(PluginCall call) {
168
- if (this.hasCamera(call) == false) {
169
- call.reject("Camera is not running");
170
- return;
171
- }
172
-
173
- Camera camera = fragment.getCamera();
174
- Camera.Parameters params = camera.getParameters();
175
+ Camera camera = fragment.getCamera();
176
+ Camera.Parameters params = camera.getParameters();
177
+ List<String> supportedFlashModes;
178
+ supportedFlashModes = params.getSupportedFlashModes();
179
+ JSONArray jsonFlashModes = new JSONArray();
175
180
 
176
- float horizontalViewAngle = params.getHorizontalViewAngle();
177
-
178
- JSObject jsObject = new JSObject();
179
- jsObject.put("result", horizontalViewAngle);
180
- call.resolve(jsObject);
181
+ if (supportedFlashModes != null) {
182
+ for (int i = 0; i < supportedFlashModes.size(); i++) {
183
+ jsonFlashModes.put(new String(supportedFlashModes.get(i)));
184
+ }
181
185
  }
182
186
 
183
- @PluginMethod
184
- public void setFlashMode(PluginCall call) {
185
- if (this.hasCamera(call) == false) {
186
- call.reject("Camera is not running");
187
- return;
188
- }
189
-
190
- String flashMode = call.getString("flashMode");
191
- if (flashMode == null || flashMode.isEmpty() == true) {
192
- call.reject("flashMode required parameter is missing");
193
- return;
194
- }
195
-
196
- Camera camera = fragment.getCamera();
197
- Camera.Parameters params = camera.getParameters();
198
-
199
- List<String> supportedFlashModes;
200
- supportedFlashModes = camera.getParameters().getSupportedFlashModes();
201
- if (supportedFlashModes.indexOf(flashMode) > -1) {
202
- params.setFlashMode(flashMode);
203
- } else {
204
- call.reject("Flash mode not recognised: " + flashMode);
205
- return;
206
- }
187
+ JSObject jsObject = new JSObject();
188
+ jsObject.put("result", jsonFlashModes);
189
+ call.resolve(jsObject);
190
+ }
207
191
 
208
- fragment.setCameraParameters(params);
209
-
210
- call.resolve();
192
+ @PluginMethod
193
+ public void getHorizontalFov(PluginCall call) {
194
+ if (this.hasCamera(call) == false) {
195
+ call.reject("Camera is not running");
196
+ return;
211
197
  }
212
198
 
213
- @PluginMethod
214
- public void startRecordVideo(final PluginCall call) {
215
- if (this.hasCamera(call) == false) {
216
- call.reject("Camera is not running");
217
- return;
218
- }
219
- final String filename = "videoTmp";
220
- VIDEO_FILE_PATH = getActivity().getCacheDir().toString() + "/";
221
-
222
- final String position = call.getString("position", "front");
223
- final Integer width = call.getInt("width", 0);
224
- final Integer height = call.getInt("height", 0);
225
- final Boolean withFlash = call.getBoolean("withFlash", false);
226
- final Integer maxDuration = call.getInt("maxDuration", 0);
227
- // final Integer quality = call.getInt("quality", 0);
228
- bridge.saveCall(call);
229
- recordCallbackId = call.getCallbackId();
230
-
231
- bridge
232
- .getActivity()
233
- .runOnUiThread(
234
- new Runnable() {
235
- @Override
236
- public void run() {
237
- // fragment.startRecord(getFilePath(filename), position, width, height, quality, withFlash);
238
- fragment.startRecord(getFilePath(filename), position, width, height, 70, withFlash, maxDuration);
239
- }
240
- }
241
- );
242
-
243
- call.resolve();
244
- }
199
+ Camera camera = fragment.getCamera();
200
+ Camera.Parameters params = camera.getParameters();
245
201
 
246
- @PluginMethod
247
- public void stopRecordVideo(PluginCall call) {
248
- if (this.hasCamera(call) == false) {
249
- call.reject("Camera is not running");
250
- return;
251
- }
202
+ float horizontalViewAngle = params.getHorizontalViewAngle();
252
203
 
253
- System.out.println("stopRecordVideo - Callbackid=" + call.getCallbackId());
204
+ JSObject jsObject = new JSObject();
205
+ jsObject.put("result", horizontalViewAngle);
206
+ call.resolve(jsObject);
207
+ }
254
208
 
255
- bridge.saveCall(call);
256
- recordCallbackId = call.getCallbackId();
257
-
258
- // bridge.getActivity().runOnUiThread(new Runnable() {
259
- // @Override
260
- // public void run() {
261
- // fragment.stopRecord();
262
- // }
263
- // });
209
+ @PluginMethod
210
+ public void setFlashMode(PluginCall call) {
211
+ if (this.hasCamera(call) == false) {
212
+ call.reject("Camera is not running");
213
+ return;
214
+ }
264
215
 
265
- fragment.stopRecord();
266
- // call.resolve();
216
+ String flashMode = call.getString("flashMode");
217
+ if (flashMode == null || flashMode.isEmpty() == true) {
218
+ call.reject("flashMode required parameter is missing");
219
+ return;
267
220
  }
268
221
 
269
- @PermissionCallback
270
- private void handleCameraPermissionResult(PluginCall call) {
271
- if (PermissionState.GRANTED.equals(getPermissionState(CAMERA_PERMISSION_ALIAS))) {
272
- startCamera(call);
273
- } else {
274
- Logger.debug(getLogTag(), "User denied camera permission: " + getPermissionState(CAMERA_PERMISSION_ALIAS).toString());
275
- call.reject("Permission failed: user denied access to camera.");
276
- }
222
+ Camera camera = fragment.getCamera();
223
+ Camera.Parameters params = camera.getParameters();
224
+
225
+ List<String> supportedFlashModes;
226
+ supportedFlashModes = camera.getParameters().getSupportedFlashModes();
227
+ if (
228
+ supportedFlashModes != null && supportedFlashModes.indexOf(flashMode) > -1
229
+ ) {
230
+ params.setFlashMode(flashMode);
231
+ } else {
232
+ call.reject("Flash mode not recognised: " + flashMode);
233
+ return;
277
234
  }
278
235
 
279
- private void startCamera(final PluginCall call) {
280
- String position = call.getString("position");
236
+ fragment.setCameraParameters(params);
281
237
 
282
- if (position == null || position.isEmpty() || "rear".equals(position)) {
283
- position = "back";
284
- } else {
285
- position = "front";
286
- }
238
+ call.resolve();
239
+ }
287
240
 
288
- final Integer x = call.getInt("x", 0);
289
- final Integer y = call.getInt("y", 0);
290
- final Integer width = call.getInt("width", 0);
291
- final Integer height = call.getInt("height", 0);
292
- final Integer paddingBottom = call.getInt("paddingBottom", 0);
293
- final Boolean toBack = call.getBoolean("toBack", false);
294
- final Boolean storeToFile = call.getBoolean("storeToFile", false);
295
- final Boolean enableOpacity = call.getBoolean("enableOpacity", false);
296
- final Boolean enableZoom = call.getBoolean("enableZoom", false);
297
- final Boolean disableExifHeaderStripping = call.getBoolean("disableExifHeaderStripping", true);
298
- final Boolean lockOrientation = call.getBoolean("lockAndroidOrientation", false);
299
- previousOrientationRequest = getBridge().getActivity().getRequestedOrientation();
300
-
301
- fragment = new CameraActivity();
302
- fragment.setEventListener(this);
303
- fragment.defaultCamera = position;
304
- fragment.tapToTakePicture = false;
305
- fragment.dragEnabled = false;
306
- fragment.tapToFocus = true;
307
- fragment.disableExifHeaderStripping = disableExifHeaderStripping;
308
- fragment.storeToFile = storeToFile;
309
- fragment.toBack = toBack;
310
- fragment.enableOpacity = enableOpacity;
311
- fragment.enableZoom = enableZoom;
312
-
313
- bridge
314
- .getActivity()
315
- .runOnUiThread(
316
- new Runnable() {
317
- @Override
318
- public void run() {
319
- DisplayMetrics metrics = getBridge().getActivity().getResources().getDisplayMetrics();
320
- // lock orientation if specified in options:
321
- if (lockOrientation) {
322
- getBridge().getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
323
- }
324
-
325
- // offset
326
- int computedX = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, x, metrics);
327
- int computedY = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, y, metrics);
328
-
329
- // size
330
- int computedWidth;
331
- int computedHeight;
332
- int computedPaddingBottom;
333
-
334
- if (paddingBottom != 0) {
335
- computedPaddingBottom = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, paddingBottom, metrics);
336
- } else {
337
- computedPaddingBottom = 0;
338
- }
339
-
340
- if (width != 0) {
341
- computedWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, width, metrics);
342
- } else {
343
- Display defaultDisplay = getBridge().getActivity().getWindowManager().getDefaultDisplay();
344
- final Point size = new Point();
345
- defaultDisplay.getSize(size);
346
-
347
- computedWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, size.x, metrics);
348
- }
349
-
350
- if (height != 0) {
351
- computedHeight =
352
- (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, height, metrics) - computedPaddingBottom;
353
- } else {
354
- Display defaultDisplay = getBridge().getActivity().getWindowManager().getDefaultDisplay();
355
- final Point size = new Point();
356
- defaultDisplay.getSize(size);
357
-
358
- computedHeight =
359
- (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, size.y, metrics) - computedPaddingBottom;
360
- }
361
-
362
- fragment.setRect(computedX, computedY, computedWidth, computedHeight);
363
-
364
- FrameLayout containerView = getBridge().getActivity().findViewById(containerViewId);
365
- if (containerView == null) {
366
- containerView = new FrameLayout(getActivity().getApplicationContext());
367
- containerView.setId(containerViewId);
368
-
369
- getBridge().getWebView().setBackgroundColor(Color.TRANSPARENT);
370
- ((ViewGroup) getBridge().getWebView().getParent()).addView(containerView);
371
- if (toBack == true) {
372
- getBridge().getWebView().getParent().bringChildToFront(getBridge().getWebView());
373
- setupBroadcast();
374
- }
375
-
376
- FragmentManager fragmentManager = getBridge().getActivity().getFragmentManager();
377
- FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
378
- fragmentTransaction.add(containerView.getId(), fragment);
379
- fragmentTransaction.commit();
380
-
381
- // NOTE: we don't return invoke call.resolve here because it must be invoked in onCameraStarted
382
- // otherwise the plugin start method might resolve/return before the camera is actually set in CameraActivity
383
- // onResume method (see this line mCamera = Camera.open(defaultCameraId);) and the next subsequent plugin
384
- // method invocations (for example, getSupportedFlashModes) might fails with "Camera is not running" error
385
- // because camera is not available yet and hasCamera method will return false
386
- // Please also see https://developer.android.com/reference/android/hardware/Camera.html#open%28int%29
387
- bridge.saveCall(call);
388
- cameraStartCallbackId = call.getCallbackId();
389
- } else {
390
- call.reject("camera already started");
391
- }
392
- }
393
- }
394
- );
241
+ @PluginMethod
242
+ public void startRecordVideo(final PluginCall call) {
243
+ if (this.hasCamera(call) == false) {
244
+ call.reject("Camera is not running");
245
+ return;
395
246
  }
247
+ final String filename = "videoTmp";
248
+ VIDEO_FILE_PATH = getActivity().getCacheDir().toString() + "/";
249
+
250
+ final String position = call.getString("position", "front");
251
+ final Integer width = call.getInt("width", 0);
252
+ final Integer height = call.getInt("height", 0);
253
+ final Boolean withFlash = call.getBoolean("withFlash", false);
254
+ final Integer maxDuration = call.getInt("maxDuration", 0);
255
+ // final Integer quality = call.getInt("quality", 0);
256
+ bridge.saveCall(call);
257
+ recordCallbackId = call.getCallbackId();
258
+
259
+ bridge
260
+ .getActivity()
261
+ .runOnUiThread(
262
+ new Runnable() {
263
+ @Override
264
+ public void run() {
265
+ // fragment.startRecord(getFilePath(filename), position, width, height, quality, withFlash);
266
+ fragment.startRecord(
267
+ getFilePath(filename),
268
+ position,
269
+ width,
270
+ height,
271
+ 70,
272
+ withFlash,
273
+ maxDuration
274
+ );
275
+ }
276
+ }
277
+ );
396
278
 
397
- @Override
398
- protected void handleOnResume() {
399
- super.handleOnResume();
400
- }
279
+ call.resolve();
280
+ }
401
281
 
402
- @Override
403
- public void onPictureTaken(String originalPicture) {
404
- JSObject jsObject = new JSObject();
405
- jsObject.put("value", originalPicture);
406
- bridge.getSavedCall(captureCallbackId).resolve(jsObject);
282
+ @PluginMethod
283
+ public void stopRecordVideo(PluginCall call) {
284
+ if (this.hasCamera(call) == false) {
285
+ call.reject("Camera is not running");
286
+ return;
407
287
  }
408
288
 
409
- @Override
410
- public void onPictureTakenError(String message) {
411
- bridge.getSavedCall(captureCallbackId).reject(message);
289
+ System.out.println("stopRecordVideo - Callbackid=" + call.getCallbackId());
290
+
291
+ bridge.saveCall(call);
292
+ recordCallbackId = call.getCallbackId();
293
+
294
+ // bridge.getActivity().runOnUiThread(new Runnable() {
295
+ // @Override
296
+ // public void run() {
297
+ // fragment.stopRecord();
298
+ // }
299
+ // });
300
+
301
+ fragment.stopRecord();
302
+ // call.resolve();
303
+ }
304
+
305
+ @PermissionCallback
306
+ private void handleCameraPermissionResult(PluginCall call) {
307
+ if (
308
+ PermissionState.GRANTED.equals(
309
+ getPermissionState(CAMERA_PERMISSION_ALIAS)
310
+ )
311
+ ) {
312
+ startCamera(call);
313
+ } else {
314
+ Logger.debug(
315
+ getLogTag(),
316
+ "User denied camera permission: " +
317
+ getPermissionState(CAMERA_PERMISSION_ALIAS).toString()
318
+ );
319
+ call.reject("Permission failed: user denied access to camera.");
412
320
  }
321
+ }
413
322
 
414
- @Override
415
- public void onSnapshotTaken(String originalPicture) {
416
- JSObject jsObject = new JSObject();
417
- jsObject.put("value", originalPicture);
418
- bridge.getSavedCall(snapshotCallbackId).resolve(jsObject);
419
- }
323
+ private void startCamera(final PluginCall call) {
324
+ String position = call.getString("position");
420
325
 
421
- @Override
422
- public void onSnapshotTakenError(String message) {
423
- bridge.getSavedCall(snapshotCallbackId).reject(message);
326
+ if (position == null || position.isEmpty() || "rear".equals(position)) {
327
+ position = "back";
328
+ } else {
329
+ position = "front";
424
330
  }
425
331
 
426
- @Override
427
- public void onFocusSet(int pointX, int pointY) {}
428
-
429
- @Override
430
- public void onFocusSetError(String message) {}
431
-
432
- @Override
433
- public void onBackButton() {}
332
+ final Integer x = call.getInt("x", 0);
333
+ final Integer y = call.getInt("y", 0);
334
+ final Integer width = call.getInt("width", 0);
335
+ final Integer height = call.getInt("height", 0);
336
+ final Integer paddingBottom = call.getInt("paddingBottom", 0);
337
+ final Boolean toBack = call.getBoolean("toBack", false);
338
+ final Boolean storeToFile = call.getBoolean("storeToFile", false);
339
+ final Boolean enableOpacity = call.getBoolean("enableOpacity", false);
340
+ final Boolean enableZoom = call.getBoolean("enableZoom", false);
341
+ final Boolean disableExifHeaderStripping = call.getBoolean(
342
+ "disableExifHeaderStripping",
343
+ true
344
+ );
345
+ final Boolean lockOrientation = call.getBoolean(
346
+ "lockAndroidOrientation",
347
+ false
348
+ );
349
+ previousOrientationRequest =
350
+ getBridge().getActivity().getRequestedOrientation();
351
+
352
+ fragment = new CameraActivity();
353
+ fragment.setEventListener(this);
354
+ fragment.defaultCamera = position;
355
+ fragment.tapToTakePicture = false;
356
+ fragment.dragEnabled = false;
357
+ fragment.tapToFocus = true;
358
+ fragment.disableExifHeaderStripping = disableExifHeaderStripping;
359
+ fragment.storeToFile = storeToFile;
360
+ fragment.toBack = toBack;
361
+ fragment.enableOpacity = enableOpacity;
362
+ fragment.enableZoom = enableZoom;
363
+
364
+ bridge
365
+ .getActivity()
366
+ .runOnUiThread(
367
+ new Runnable() {
368
+ @Override
369
+ public void run() {
370
+ DisplayMetrics metrics = getBridge()
371
+ .getActivity()
372
+ .getResources()
373
+ .getDisplayMetrics();
374
+ // lock orientation if specified in options:
375
+ if (lockOrientation) {
376
+ getBridge()
377
+ .getActivity()
378
+ .setRequestedOrientation(
379
+ ActivityInfo.SCREEN_ORIENTATION_LOCKED
380
+ );
381
+ }
434
382
 
435
- @Override
436
- public void onCameraStarted() {
437
- PluginCall pluginCall = bridge.getSavedCall(cameraStartCallbackId);
438
- pluginCall.resolve();
439
- bridge.releaseCall(pluginCall);
440
- }
383
+ // offset
384
+ int computedX = (int) TypedValue.applyDimension(
385
+ TypedValue.COMPLEX_UNIT_DIP,
386
+ x,
387
+ metrics
388
+ );
389
+ int computedY = (int) TypedValue.applyDimension(
390
+ TypedValue.COMPLEX_UNIT_DIP,
391
+ y,
392
+ metrics
393
+ );
441
394
 
442
- @Override
443
- public void onStartRecordVideo() {}
395
+ // size
396
+ int computedWidth;
397
+ int computedHeight;
398
+ int computedPaddingBottom;
399
+
400
+ if (paddingBottom != 0) {
401
+ computedPaddingBottom =
402
+ (int) TypedValue.applyDimension(
403
+ TypedValue.COMPLEX_UNIT_DIP,
404
+ paddingBottom,
405
+ metrics
406
+ );
407
+ } else {
408
+ computedPaddingBottom = 0;
409
+ }
444
410
 
445
- @Override
446
- public void onStartRecordVideoError(String message) {
447
- bridge.getSavedCall(recordCallbackId).reject(message);
448
- }
411
+ if (width != 0) {
412
+ computedWidth =
413
+ (int) TypedValue.applyDimension(
414
+ TypedValue.COMPLEX_UNIT_DIP,
415
+ width,
416
+ metrics
417
+ );
418
+ } else {
419
+ Display defaultDisplay = getBridge()
420
+ .getActivity()
421
+ .getWindowManager()
422
+ .getDefaultDisplay();
423
+ final Point size = new Point();
424
+ defaultDisplay.getSize(size);
425
+
426
+ computedWidth =
427
+ (int) TypedValue.applyDimension(
428
+ TypedValue.COMPLEX_UNIT_PX,
429
+ size.x,
430
+ metrics
431
+ );
432
+ }
449
433
 
450
- @Override
451
- public void onStopRecordVideo(String file) {
452
- PluginCall pluginCall = bridge.getSavedCall(recordCallbackId);
453
- JSObject jsObject = new JSObject();
454
- jsObject.put("videoFilePath", file);
455
- pluginCall.resolve(jsObject);
456
- }
434
+ if (height != 0) {
435
+ computedHeight =
436
+ (int) TypedValue.applyDimension(
437
+ TypedValue.COMPLEX_UNIT_DIP,
438
+ height,
439
+ metrics
440
+ ) -
441
+ computedPaddingBottom;
442
+ } else {
443
+ Display defaultDisplay = getBridge()
444
+ .getActivity()
445
+ .getWindowManager()
446
+ .getDefaultDisplay();
447
+ final Point size = new Point();
448
+ defaultDisplay.getSize(size);
449
+
450
+ computedHeight =
451
+ (int) TypedValue.applyDimension(
452
+ TypedValue.COMPLEX_UNIT_PX,
453
+ size.y,
454
+ metrics
455
+ ) -
456
+ computedPaddingBottom;
457
+ }
457
458
 
458
- @Override
459
- public void onStopRecordVideoError(String error) {
460
- bridge.getSavedCall(recordCallbackId).reject(error);
461
- }
459
+ fragment.setRect(
460
+ computedX,
461
+ computedY,
462
+ computedWidth,
463
+ computedHeight
464
+ );
462
465
 
463
- private boolean hasView(PluginCall call) {
464
- if (fragment == null) {
465
- return false;
466
+ FrameLayout containerView = getBridge()
467
+ .getActivity()
468
+ .findViewById(containerViewId);
469
+ if (containerView == null) {
470
+ containerView =
471
+ new FrameLayout(getActivity().getApplicationContext());
472
+ containerView.setId(containerViewId);
473
+
474
+ getBridge().getWebView().setBackgroundColor(Color.TRANSPARENT);
475
+ ((ViewGroup) getBridge().getWebView().getParent()).addView(
476
+ containerView
477
+ );
478
+ if (toBack == true) {
479
+ getBridge()
480
+ .getWebView()
481
+ .getParent()
482
+ .bringChildToFront(getBridge().getWebView());
483
+ setupBroadcast();
484
+ }
485
+
486
+ FragmentManager fragmentManager = getBridge()
487
+ .getActivity()
488
+ .getFragmentManager();
489
+ FragmentTransaction fragmentTransaction =
490
+ fragmentManager.beginTransaction();
491
+ fragmentTransaction.add(containerView.getId(), fragment);
492
+ fragmentTransaction.commit();
493
+
494
+ // NOTE: we don't return invoke call.resolve here because it must be invoked in onCameraStarted
495
+ // otherwise the plugin start method might resolve/return before the camera is actually set in CameraActivity
496
+ // onResume method (see this line mCamera = Camera.open(defaultCameraId);) and the next subsequent plugin
497
+ // method invocations (for example, getSupportedFlashModes) might fails with "Camera is not running" error
498
+ // because camera is not available yet and hasCamera method will return false
499
+ // Please also see https://developer.android.com/reference/android/hardware/Camera.html#open%28int%29
500
+ bridge.saveCall(call);
501
+ cameraStartCallbackId = call.getCallbackId();
502
+ } else {
503
+ call.reject("camera already started");
504
+ }
505
+ }
466
506
  }
467
-
468
- return true;
507
+ );
508
+ }
509
+
510
+ @Override
511
+ protected void handleOnResume() {
512
+ super.handleOnResume();
513
+ }
514
+
515
+ @Override
516
+ public void onPictureTaken(String originalPicture) {
517
+ JSObject jsObject = new JSObject();
518
+ jsObject.put("value", originalPicture);
519
+ bridge.getSavedCall(captureCallbackId).resolve(jsObject);
520
+ }
521
+
522
+ @Override
523
+ public void onPictureTakenError(String message) {
524
+ bridge.getSavedCall(captureCallbackId).reject(message);
525
+ }
526
+
527
+ @Override
528
+ public void onSnapshotTaken(String originalPicture) {
529
+ JSObject jsObject = new JSObject();
530
+ jsObject.put("value", originalPicture);
531
+ bridge.getSavedCall(snapshotCallbackId).resolve(jsObject);
532
+ }
533
+
534
+ @Override
535
+ public void onSnapshotTakenError(String message) {
536
+ bridge.getSavedCall(snapshotCallbackId).reject(message);
537
+ }
538
+
539
+ @Override
540
+ public void onFocusSet(int pointX, int pointY) {}
541
+
542
+ @Override
543
+ public void onFocusSetError(String message) {}
544
+
545
+ @Override
546
+ public void onBackButton() {}
547
+
548
+ @Override
549
+ public void onCameraStarted() {
550
+ PluginCall pluginCall = bridge.getSavedCall(cameraStartCallbackId);
551
+ pluginCall.resolve();
552
+ bridge.releaseCall(pluginCall);
553
+ }
554
+
555
+ @Override
556
+ public void onStartRecordVideo() {}
557
+
558
+ @Override
559
+ public void onStartRecordVideoError(String message) {
560
+ bridge.getSavedCall(recordCallbackId).reject(message);
561
+ }
562
+
563
+ @Override
564
+ public void onStopRecordVideo(String file) {
565
+ PluginCall pluginCall = bridge.getSavedCall(recordCallbackId);
566
+ JSObject jsObject = new JSObject();
567
+ jsObject.put("videoFilePath", file);
568
+ pluginCall.resolve(jsObject);
569
+ }
570
+
571
+ @Override
572
+ public void onStopRecordVideoError(String error) {
573
+ bridge.getSavedCall(recordCallbackId).reject(error);
574
+ }
575
+
576
+ private boolean hasView(PluginCall call) {
577
+ if (fragment == null) {
578
+ return false;
469
579
  }
470
580
 
471
- private boolean hasCamera(PluginCall call) {
472
- if (this.hasView(call) == false) {
473
- return false;
474
- }
581
+ return true;
582
+ }
475
583
 
476
- if (fragment.getCamera() == null) {
477
- return false;
478
- }
584
+ private boolean hasCamera(PluginCall call) {
585
+ if (this.hasView(call) == false) {
586
+ return false;
587
+ }
479
588
 
480
- return true;
589
+ if (fragment.getCamera() == null) {
590
+ return false;
481
591
  }
482
592
 
483
- private String getFilePath(String filename) {
484
- String fileName = filename;
593
+ return true;
594
+ }
485
595
 
486
- int i = 1;
596
+ private String getFilePath(String filename) {
597
+ String fileName = filename;
487
598
 
488
- while (new File(VIDEO_FILE_PATH + fileName + VIDEO_FILE_EXTENSION).exists()) {
489
- // Add number suffix if file exists
490
- fileName = filename + '_' + i;
491
- i++;
492
- }
599
+ int i = 1;
493
600
 
494
- return VIDEO_FILE_PATH + fileName + VIDEO_FILE_EXTENSION;
601
+ while (
602
+ new File(VIDEO_FILE_PATH + fileName + VIDEO_FILE_EXTENSION).exists()
603
+ ) {
604
+ // Add number suffix if file exists
605
+ fileName = filename + '_' + i;
606
+ i++;
495
607
  }
496
608
 
497
- private void setupBroadcast() {
498
- /** When touch event is triggered, relay it to camera view if needed so it can support pinch zoom */
499
-
500
- getBridge().getWebView().setClickable(true);
501
- getBridge()
502
- .getWebView()
503
- .setOnTouchListener(
504
- new View.OnTouchListener() {
505
- @Override
506
- public boolean onTouch(View v, MotionEvent event) {
507
- if ((null != fragment) && (fragment.toBack == true)) {
508
- fragment.frameContainerLayout.dispatchTouchEvent(event);
509
- }
510
- return false;
511
- }
512
- }
513
- );
514
- }
609
+ return VIDEO_FILE_PATH + fileName + VIDEO_FILE_EXTENSION;
610
+ }
611
+
612
+ private void setupBroadcast() {
613
+ /** When touch event is triggered, relay it to camera view if needed so it can support pinch zoom */
614
+
615
+ getBridge().getWebView().setClickable(true);
616
+ getBridge()
617
+ .getWebView()
618
+ .setOnTouchListener(
619
+ new View.OnTouchListener() {
620
+ @Override
621
+ public boolean onTouch(View v, MotionEvent event) {
622
+ if ((null != fragment) && (fragment.toBack == true)) {
623
+ fragment.frameContainerLayout.dispatchTouchEvent(event);
624
+ }
625
+ return false;
626
+ }
627
+ }
628
+ );
629
+ }
515
630
  }