@carviz/capacitor-camera-preview 7.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 (56) hide show
  1. package/CarvizCapacitorCameraPreview.podspec +17 -0
  2. package/LICENSE +22 -0
  3. package/README.md +229 -0
  4. package/android/.project +17 -0
  5. package/android/build.gradle +57 -0
  6. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  7. package/android/gradle/wrapper/gradle-wrapper.properties +8 -0
  8. package/android/gradle.properties +18 -0
  9. package/android/gradlew +248 -0
  10. package/android/gradlew.bat +92 -0
  11. package/android/proguard-rules.pro +21 -0
  12. package/android/settings.gradle +2 -0
  13. package/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java +26 -0
  14. package/android/src/main/AndroidManifest.xml +5 -0
  15. package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java +831 -0
  16. package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +396 -0
  17. package/android/src/main/java/com/ahm/capacitor/camera/preview/CustomSurfaceView.java +23 -0
  18. package/android/src/main/java/com/ahm/capacitor/camera/preview/CustomTextureView.java +29 -0
  19. package/android/src/main/java/com/ahm/capacitor/camera/preview/Preview.java +384 -0
  20. package/android/src/main/java/com/ahm/capacitor/camera/preview/TapGestureDetector.java +24 -0
  21. package/android/src/main/res/layout/bridge_layout_main.xml +15 -0
  22. package/android/src/main/res/layout/camera_activity.xml +68 -0
  23. package/android/src/main/res/values/camera_ids.xml +4 -0
  24. package/android/src/main/res/values/camera_theme.xml +9 -0
  25. package/android/src/main/res/values/colors.xml +3 -0
  26. package/android/src/main/res/values/strings.xml +3 -0
  27. package/android/src/main/res/values/styles.xml +3 -0
  28. package/android/src/test/java/com/getcapacitor/ExampleUnitTest.java +18 -0
  29. package/dist/esm/definitions.d.ts +86 -0
  30. package/dist/esm/definitions.js +2 -0
  31. package/dist/esm/definitions.js.map +1 -0
  32. package/dist/esm/index.d.ts +4 -0
  33. package/dist/esm/index.js +7 -0
  34. package/dist/esm/index.js.map +1 -0
  35. package/dist/esm/web.d.ts +24 -0
  36. package/dist/esm/web.js +120 -0
  37. package/dist/esm/web.js.map +1 -0
  38. package/dist/plugin.cjs.js +134 -0
  39. package/dist/plugin.cjs.js.map +1 -0
  40. package/dist/plugin.js +137 -0
  41. package/dist/plugin.js.map +1 -0
  42. package/ios/Plugin/CameraController.swift +483 -0
  43. package/ios/Plugin/Info.plist +24 -0
  44. package/ios/Plugin/Plugin.h +10 -0
  45. package/ios/Plugin/Plugin.m +16 -0
  46. package/ios/Plugin/Plugin.swift +324 -0
  47. package/ios/Plugin/UIImage.swift +56 -0
  48. package/ios/Plugin.xcodeproj/project.pbxproj +599 -0
  49. package/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  50. package/ios/Plugin.xcworkspace/contents.xcworkspacedata +10 -0
  51. package/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  52. package/ios/PluginTests/Info.plist +22 -0
  53. package/ios/PluginTests/PluginTests.swift +16 -0
  54. package/ios/Podfile +16 -0
  55. package/ios/Podfile.lock +22 -0
  56. package/package.json +85 -0
@@ -0,0 +1,396 @@
1
+ package com.ahm.capacitor.camera.preview;
2
+
3
+ import static android.Manifest.permission.CAMERA;
4
+
5
+ import android.app.FragmentManager;
6
+ import android.app.FragmentTransaction;
7
+ import android.content.pm.ActivityInfo;
8
+ import android.graphics.Color;
9
+ import android.graphics.Point;
10
+ import android.hardware.Camera;
11
+ import android.util.DisplayMetrics;
12
+ import android.util.TypedValue;
13
+ import android.view.Display;
14
+ import android.view.MotionEvent;
15
+ import android.view.View;
16
+ import android.view.ViewGroup;
17
+ import android.widget.FrameLayout;
18
+ import com.getcapacitor.JSObject;
19
+ import com.getcapacitor.Logger;
20
+ import com.getcapacitor.PermissionState;
21
+ import com.getcapacitor.Plugin;
22
+ import com.getcapacitor.PluginCall;
23
+ import com.getcapacitor.PluginMethod;
24
+ import com.getcapacitor.annotation.CapacitorPlugin;
25
+ import com.getcapacitor.annotation.Permission;
26
+ import com.getcapacitor.annotation.PermissionCallback;
27
+ import java.util.List;
28
+ import org.json.JSONArray;
29
+
30
+ @CapacitorPlugin(name = "CameraPreview", permissions = { @Permission(strings = { CAMERA }, alias = CameraPreview.CAMERA_PERMISSION_ALIAS) })
31
+ public class CameraPreview extends Plugin implements CameraActivity.CameraPreviewListener {
32
+
33
+ static final String CAMERA_PERMISSION_ALIAS = "camera";
34
+
35
+ private String captureCallbackId = "";
36
+ private String snapshotCallbackId = "";
37
+ private String cameraStartCallbackId = "";
38
+
39
+ // keep track of previously specified orientation to support locking orientation:
40
+ private int previousOrientationRequest = -1;
41
+
42
+ private CameraActivity fragment;
43
+ private int containerViewId = 20;
44
+
45
+ @PluginMethod
46
+ public void start(PluginCall call) {
47
+ if (PermissionState.GRANTED.equals(getPermissionState(CAMERA_PERMISSION_ALIAS))) {
48
+ startCamera(call);
49
+ } else {
50
+ requestPermissionForAlias(CAMERA_PERMISSION_ALIAS, call, "handleCameraPermissionResult");
51
+ }
52
+ }
53
+
54
+ @PluginMethod
55
+ public void flip(PluginCall call) {
56
+ try {
57
+ fragment.switchCamera();
58
+ call.resolve();
59
+ } catch (Exception e) {
60
+ Logger.debug(getLogTag(), "Camera flip exception: " + e);
61
+ call.reject("failed to flip camera");
62
+ }
63
+ }
64
+
65
+ @PluginMethod
66
+ public void setOpacity(PluginCall call) {
67
+ if (this.hasCamera(call) == false) {
68
+ return;
69
+ }
70
+
71
+ bridge.saveCall(call);
72
+ Float opacity = call.getFloat("opacity", 1F);
73
+ fragment.setOpacity(opacity);
74
+ }
75
+
76
+ @PluginMethod
77
+ public void capture(PluginCall call) {
78
+ if (this.hasCamera(call) == false) {
79
+ call.reject("Camera is not running");
80
+ return;
81
+ }
82
+ bridge.saveCall(call);
83
+ captureCallbackId = call.getCallbackId();
84
+
85
+ Integer quality = call.getInt("quality", 85);
86
+ // Image Dimensions - Optional
87
+ Integer width = call.getInt("width", 0);
88
+ Integer height = call.getInt("height", 0);
89
+ fragment.takePicture(width, height, quality);
90
+ }
91
+
92
+ @PluginMethod
93
+ public void captureSample(PluginCall call) {
94
+ if (this.hasCamera(call) == false) {
95
+ call.reject("Camera is not running");
96
+ return;
97
+ }
98
+ bridge.saveCall(call);
99
+ snapshotCallbackId = call.getCallbackId();
100
+
101
+ Integer quality = call.getInt("quality", 85);
102
+ fragment.takeSnapshot(quality);
103
+ }
104
+
105
+ @PluginMethod
106
+ public void stop(final PluginCall call) {
107
+ bridge
108
+ .getActivity()
109
+ .runOnUiThread(
110
+ new Runnable() {
111
+ @Override
112
+ public void run() {
113
+ FrameLayout containerView = getBridge().getActivity().findViewById(containerViewId);
114
+
115
+ // allow orientation changes after closing camera:
116
+ getBridge().getActivity().setRequestedOrientation(previousOrientationRequest);
117
+
118
+ if (containerView != null) {
119
+ ((ViewGroup) getBridge().getWebView().getParent()).removeView(containerView);
120
+ getBridge().getWebView().setBackgroundColor(Color.WHITE);
121
+ FragmentManager fragmentManager = getActivity().getFragmentManager();
122
+ FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
123
+ fragmentTransaction.remove(fragment);
124
+ fragmentTransaction.commit();
125
+ fragment = null;
126
+
127
+ call.resolve();
128
+ } else {
129
+ call.reject("camera already stopped");
130
+ }
131
+ }
132
+ }
133
+ );
134
+ }
135
+
136
+ @PluginMethod
137
+ public void getSupportedFlashModes(PluginCall call) {
138
+ if (this.hasCamera(call) == false) {
139
+ call.reject("Camera is not running");
140
+ return;
141
+ }
142
+
143
+ Camera camera = fragment.getCamera();
144
+ Camera.Parameters params = camera.getParameters();
145
+ List<String> supportedFlashModes;
146
+ supportedFlashModes = params.getSupportedFlashModes();
147
+ JSONArray jsonFlashModes = new JSONArray();
148
+
149
+ if (supportedFlashModes != null) {
150
+ for (int i = 0; i < supportedFlashModes.size(); i++) {
151
+ jsonFlashModes.put(new String(supportedFlashModes.get(i)));
152
+ }
153
+ }
154
+
155
+ JSObject jsObject = new JSObject();
156
+ jsObject.put("result", jsonFlashModes);
157
+ call.resolve(jsObject);
158
+ }
159
+
160
+ @PluginMethod
161
+ public void setFlashMode(PluginCall call) {
162
+ if (!this.hasCamera(call)) {
163
+ call.reject("Camera is not running");
164
+ return;
165
+ }
166
+
167
+ String flashMode = call.getString("flashMode");
168
+ if (flashMode == null || flashMode.isEmpty()) {
169
+ call.reject("flashMode required parameter is missing");
170
+ return;
171
+ }
172
+
173
+ Camera camera = fragment.getCamera();
174
+ Camera.Parameters params = camera.getParameters();
175
+
176
+ List<String> supportedFlashModes;
177
+ supportedFlashModes = camera.getParameters().getSupportedFlashModes();
178
+
179
+ if (supportedFlashModes != null && supportedFlashModes.contains(flashMode)) {
180
+ params.setFlashMode(flashMode);
181
+ } else {
182
+ call.reject("Flash mode not recognized: " + flashMode);
183
+ return;
184
+ }
185
+
186
+ fragment.setCameraParameters(params);
187
+
188
+ call.resolve();
189
+ }
190
+
191
+ @PermissionCallback
192
+ private void handleCameraPermissionResult(PluginCall call) {
193
+ if (PermissionState.GRANTED.equals(getPermissionState(CAMERA_PERMISSION_ALIAS))) {
194
+ startCamera(call);
195
+ } else {
196
+ Logger.debug(getLogTag(), "User denied camera permission: " + getPermissionState(CAMERA_PERMISSION_ALIAS).toString());
197
+ call.reject("Permission failed: user denied access to camera.");
198
+ }
199
+ }
200
+
201
+ private void startCamera(final PluginCall call) {
202
+ String position = call.getString("position");
203
+
204
+ if (position == null || position.isEmpty() || "rear".equals(position)) {
205
+ position = "back";
206
+ } else {
207
+ position = "front";
208
+ }
209
+
210
+ final Integer x = call.getInt("x", 0);
211
+ final Integer y = call.getInt("y", 0);
212
+ final Integer width = call.getInt("width", 0);
213
+ final Integer height = call.getInt("height", 0);
214
+ final Integer paddingBottom = call.getInt("paddingBottom", 0);
215
+ final Boolean toBack = call.getBoolean("toBack", false);
216
+ final Boolean storeToFile = call.getBoolean("storeToFile", false);
217
+ final Boolean enableOpacity = call.getBoolean("enableOpacity", false);
218
+ final Boolean enableZoom = call.getBoolean("enableZoom", false);
219
+ final Boolean disableExifHeaderStripping = call.getBoolean("disableExifHeaderStripping", true);
220
+ final Boolean lockOrientation = call.getBoolean("lockAndroidOrientation", false);
221
+ previousOrientationRequest = getBridge().getActivity().getRequestedOrientation();
222
+
223
+ fragment = new CameraActivity();
224
+ fragment.setEventListener(this);
225
+ fragment.defaultCamera = position;
226
+ fragment.tapToTakePicture = false;
227
+ fragment.dragEnabled = false;
228
+ fragment.tapToFocus = true;
229
+ fragment.disableExifHeaderStripping = disableExifHeaderStripping;
230
+ fragment.storeToFile = storeToFile;
231
+ fragment.toBack = toBack;
232
+ fragment.enableOpacity = enableOpacity;
233
+ fragment.enableZoom = enableZoom;
234
+
235
+ bridge
236
+ .getActivity()
237
+ .runOnUiThread(
238
+ new Runnable() {
239
+ @Override
240
+ public void run() {
241
+ DisplayMetrics metrics = getBridge().getActivity().getResources().getDisplayMetrics();
242
+ // lock orientation if specified in options:
243
+ if (lockOrientation) {
244
+ getBridge().getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
245
+ }
246
+
247
+ // offset
248
+ int computedX = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, x, metrics);
249
+ int computedY = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, y, metrics);
250
+
251
+ // size
252
+ int computedWidth;
253
+ int computedHeight;
254
+ int computedPaddingBottom;
255
+
256
+ if (paddingBottom != 0) {
257
+ computedPaddingBottom = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, paddingBottom, metrics);
258
+ } else {
259
+ computedPaddingBottom = 0;
260
+ }
261
+
262
+ if (width != 0) {
263
+ computedWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, width, metrics);
264
+ } else {
265
+ Display defaultDisplay = getBridge().getActivity().getWindowManager().getDefaultDisplay();
266
+ final Point size = new Point();
267
+ defaultDisplay.getSize(size);
268
+
269
+ computedWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, size.x, metrics);
270
+ }
271
+
272
+ if (height != 0) {
273
+ computedHeight =
274
+ (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, height, metrics) - computedPaddingBottom;
275
+ } else {
276
+ Display defaultDisplay = getBridge().getActivity().getWindowManager().getDefaultDisplay();
277
+ final Point size = new Point();
278
+ defaultDisplay.getSize(size);
279
+
280
+ computedHeight =
281
+ (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, size.y, metrics) - computedPaddingBottom;
282
+ }
283
+
284
+ fragment.setRect(computedX, computedY, computedWidth, computedHeight);
285
+
286
+ FrameLayout containerView = getBridge().getActivity().findViewById(containerViewId);
287
+ if (containerView == null) {
288
+ containerView = new FrameLayout(getActivity().getApplicationContext());
289
+ containerView.setId(containerViewId);
290
+
291
+ getBridge().getWebView().setBackgroundColor(Color.TRANSPARENT);
292
+ ((ViewGroup) getBridge().getWebView().getParent()).addView(containerView);
293
+ if (toBack == true) {
294
+ getBridge().getWebView().getParent().bringChildToFront(getBridge().getWebView());
295
+ setupBroadcast();
296
+ }
297
+
298
+ FragmentManager fragmentManager = getBridge().getActivity().getFragmentManager();
299
+ FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
300
+ fragmentTransaction.add(containerView.getId(), fragment);
301
+ fragmentTransaction.commit();
302
+
303
+ // NOTE: we don't return invoke call.resolve here because it must be invoked in onCameraStarted
304
+ // otherwise the plugin start method might resolve/return before the camera is actually set in CameraActivity
305
+ // onResume method (see this line mCamera = Camera.open(defaultCameraId);) and the next subsequent plugin
306
+ // method invocations (for example, getSupportedFlashModes) might fails with "Camera is not running" error
307
+ // because camera is not available yet and hasCamera method will return false
308
+ // Please also see https://developer.android.com/reference/android/hardware/Camera.html#open%28int%29
309
+ bridge.saveCall(call);
310
+ cameraStartCallbackId = call.getCallbackId();
311
+ } else {
312
+ call.reject("camera already started");
313
+ }
314
+ }
315
+ }
316
+ );
317
+ }
318
+
319
+ @Override
320
+ protected void handleOnResume() {
321
+ super.handleOnResume();
322
+ }
323
+
324
+ @Override
325
+ public void onPictureTaken(String originalPicture) {
326
+ JSObject jsObject = new JSObject();
327
+ jsObject.put("value", originalPicture);
328
+ bridge.getSavedCall(captureCallbackId).resolve(jsObject);
329
+ }
330
+
331
+ @Override
332
+ public void onPictureTakenError(String message) {
333
+ bridge.getSavedCall(captureCallbackId).reject(message);
334
+ }
335
+
336
+ @Override
337
+ public void onSnapshotTaken(String originalPicture) {
338
+ JSObject jsObject = new JSObject();
339
+ jsObject.put("value", originalPicture);
340
+ bridge.getSavedCall(snapshotCallbackId).resolve(jsObject);
341
+ }
342
+
343
+ @Override
344
+ public void onSnapshotTakenError(String message) {
345
+ bridge.getSavedCall(snapshotCallbackId).reject(message);
346
+ }
347
+
348
+ @Override
349
+ public void onBackButton() {}
350
+
351
+ @Override
352
+ public void onCameraStarted() {
353
+ PluginCall pluginCall = bridge.getSavedCall(cameraStartCallbackId);
354
+ pluginCall.resolve();
355
+ bridge.releaseCall(pluginCall);
356
+ }
357
+
358
+ private boolean hasView(PluginCall call) {
359
+ if (fragment == null) {
360
+ return false;
361
+ }
362
+
363
+ return true;
364
+ }
365
+
366
+ private boolean hasCamera(PluginCall call) {
367
+ if (this.hasView(call) == false) {
368
+ return false;
369
+ }
370
+
371
+ if (fragment.getCamera() == null) {
372
+ return false;
373
+ }
374
+
375
+ return true;
376
+ }
377
+
378
+ private void setupBroadcast() {
379
+ /** When touch event is triggered, relay it to camera view if needed so it can support pinch zoom */
380
+
381
+ getBridge().getWebView().setClickable(true);
382
+ getBridge()
383
+ .getWebView()
384
+ .setOnTouchListener(
385
+ new View.OnTouchListener() {
386
+ @Override
387
+ public boolean onTouch(View v, MotionEvent event) {
388
+ if ((null != fragment) && (fragment.toBack == true)) {
389
+ fragment.frameContainerLayout.dispatchTouchEvent(event);
390
+ }
391
+ return false;
392
+ }
393
+ }
394
+ );
395
+ }
396
+ }
@@ -0,0 +1,23 @@
1
+ package com.ahm.capacitor.camera.preview;
2
+
3
+ import android.content.Context;
4
+ import android.view.SurfaceHolder;
5
+ import android.view.SurfaceView;
6
+
7
+ class CustomSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
8
+
9
+ private final String TAG = "CustomSurfaceView";
10
+
11
+ CustomSurfaceView(Context context) {
12
+ super(context);
13
+ }
14
+
15
+ @Override
16
+ public void surfaceCreated(SurfaceHolder holder) {}
17
+
18
+ @Override
19
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
20
+
21
+ @Override
22
+ public void surfaceDestroyed(SurfaceHolder holder) {}
23
+ }
@@ -0,0 +1,29 @@
1
+ package com.ahm.capacitor.camera.preview;
2
+
3
+ import android.content.Context;
4
+ import android.graphics.SurfaceTexture;
5
+ import android.view.SurfaceHolder;
6
+ import android.view.TextureView;
7
+
8
+ class CustomTextureView extends TextureView implements TextureView.SurfaceTextureListener {
9
+
10
+ private final String TAG = "CustomTextureView";
11
+
12
+ CustomTextureView(Context context) {
13
+ super(context);
14
+ }
15
+
16
+ @Override
17
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {}
18
+
19
+ @Override
20
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}
21
+
22
+ @Override
23
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
24
+ return true;
25
+ }
26
+
27
+ @Override
28
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {}
29
+ }