capacitor-plugin-camera-forked 3.0.12 → 3.0.13

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.
@@ -170,6 +170,7 @@ public class CameraPreviewPlugin extends Plugin {
170
170
 
171
171
  imageAnalysis = imageAnalysisBuilder.build();
172
172
 
173
+ // Configure image analysis for better focus performance
173
174
  imageAnalysis.setAnalyzer(exec, new ImageAnalysis.Analyzer() {
174
175
  @Override
175
176
  public void analyze(@NonNull ImageProxy image) {
@@ -297,6 +298,79 @@ public class CameraPreviewPlugin extends Plugin {
297
298
  return null;
298
299
  }
299
300
 
301
+ /**
302
+ * Initialize responsive auto-focus on camera start
303
+ */
304
+ private void initializeResponsiveAutoFocus() {
305
+ if (camera != null && previewView != null) {
306
+ try {
307
+ // Set initial focus to center for faster startup
308
+ MeteringPointFactory factory = previewView.getMeteringPointFactory();
309
+ float centerX = previewView.getWidth() / 2.0f;
310
+ float centerY = previewView.getHeight() / 2.0f;
311
+ MeteringPoint centerPoint = factory.createPoint(centerX, centerY);
312
+
313
+ // Create responsive auto-focus action with longer duration for better stability
314
+ FocusMeteringAction initialFocus = new FocusMeteringAction.Builder(centerPoint)
315
+ .setAutoCancelDuration(5, TimeUnit.SECONDS) // Increased from 1 to 5 seconds
316
+ .build();
317
+
318
+ camera.getCameraControl().startFocusAndMetering(initialFocus);
319
+
320
+ // Enable continuous auto-focus by starting a background focus monitoring
321
+ startContinuousAutoFocus();
322
+
323
+ Log.d("Camera", "Initialized responsive auto-focus with continuous monitoring");
324
+ } catch (Exception e) {
325
+ Log.e("Camera", "Failed to initialize responsive auto-focus: " + e.getMessage());
326
+ }
327
+ }
328
+ }
329
+
330
+ /**
331
+ * Start continuous auto-focus monitoring for better focus stability
332
+ */
333
+ private void startContinuousAutoFocus() {
334
+ if (camera != null && previewView != null) {
335
+ // Use a separate executor for continuous focus to avoid blocking
336
+ ExecutorService focusExecutor = Executors.newSingleThreadExecutor();
337
+
338
+ focusExecutor.execute(new Runnable() {
339
+ @Override
340
+ public void run() {
341
+ try {
342
+ while (camera != null && camera.getCameraInfo().getCameraState().getValue().getType() == CameraState.Type.OPEN) {
343
+ Thread.sleep(2000); // Check every 2 seconds
344
+
345
+ getActivity().runOnUiThread(new Runnable() {
346
+ @Override
347
+ public void run() {
348
+ try {
349
+ // Trigger auto-focus at center to maintain continuous focus
350
+ MeteringPointFactory factory = previewView.getMeteringPointFactory();
351
+ float centerX = previewView.getWidth() / 2.0f;
352
+ float centerY = previewView.getHeight() / 2.0f;
353
+ MeteringPoint centerPoint = factory.createPoint(centerX, centerY);
354
+
355
+ FocusMeteringAction continuousAction = new FocusMeteringAction.Builder(centerPoint)
356
+ .setAutoCancelDuration(3, TimeUnit.SECONDS)
357
+ .build();
358
+
359
+ camera.getCameraControl().startFocusAndMetering(continuousAction);
360
+ } catch (Exception e) {
361
+ Log.d("Camera", "Continuous focus update failed: " + e.getMessage());
362
+ }
363
+ }
364
+ });
365
+ }
366
+ } catch (InterruptedException e) {
367
+ Log.d("Camera", "Continuous auto-focus stopped");
368
+ }
369
+ }
370
+ });
371
+ }
372
+ }
373
+
300
374
  @PluginMethod
301
375
  public void startCamera(PluginCall call) {
302
376
  getActivity().runOnUiThread(new Runnable() {
@@ -305,6 +379,10 @@ public class CameraPreviewPlugin extends Plugin {
305
379
  camera = cameraProvider.bindToLifecycle((LifecycleOwner) getContext(), cameraSelector, useCaseGroup);
306
380
  previewView.setVisibility(View.VISIBLE);
307
381
  makeWebViewTransparent();
382
+
383
+ // Initialize responsive auto-focus for better performance
384
+ initializeResponsiveAutoFocus();
385
+
308
386
  triggerOnPlayed();
309
387
  call.resolve();
310
388
  } catch (Exception e) {
@@ -408,6 +486,9 @@ public class CameraPreviewPlugin extends Plugin {
408
486
  @Override
409
487
  public void run() {
410
488
  try {
489
+ // Cancel any existing focus operations for faster transitions
490
+ camera.getCameraControl().cancelFocusAndMetering();
491
+
411
492
  // Use PreviewView's built-in MeteringPointFactory for proper coordinate transformation
412
493
  MeteringPointFactory factory = previewView.getMeteringPointFactory();
413
494
 
@@ -417,24 +498,25 @@ public class CameraPreviewPlugin extends Plugin {
417
498
 
418
499
  MeteringPoint focusPoint = factory.createPoint(previewX, previewY);
419
500
 
420
- // Get configurable options
501
+ // Get configurable options with improved defaults for better focus stability
421
502
  boolean includeExposure = Boolean.TRUE.equals(call.getBoolean("includeExposure", true));
422
503
  Integer autoCancelDurationParam = call.getInt("autoCancelDurationSeconds");
423
- int autoCancelDuration = autoCancelDurationParam != null ? autoCancelDurationParam : 3;
504
+ // Increased to 4 seconds for better focus stability and manual control
505
+ int autoCancelDuration = autoCancelDurationParam != null ? autoCancelDurationParam : 4;
424
506
 
425
- // Build the focus and metering action
426
- FocusMeteringAction.Builder builder = new FocusMeteringAction.Builder(focusPoint);
507
+ // Build the focus and metering action with optimized settings
508
+ FocusMeteringAction.Builder builder;
427
509
 
428
- // Set auto-focus flags
510
+ // Set auto-focus flags with optimized configuration
429
511
  if (includeExposure) {
430
512
  // Use both AF and AE flags for the same point
431
513
  builder = new FocusMeteringAction.Builder(focusPoint, FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AE);
432
514
  } else {
433
- // Use only AF flag
515
+ // Use only AF flag for faster focus-only operations
434
516
  builder = new FocusMeteringAction.Builder(focusPoint, FocusMeteringAction.FLAG_AF);
435
517
  }
436
518
 
437
- // Set auto-cancel duration
519
+ // Set shorter auto-cancel duration for responsive focus
438
520
  builder.setAutoCancelDuration(autoCancelDuration, TimeUnit.SECONDS);
439
521
 
440
522
  FocusMeteringAction action = builder.build();
@@ -442,7 +524,7 @@ public class CameraPreviewPlugin extends Plugin {
442
524
  // Start focus and metering with result callback
443
525
  ListenableFuture<FocusMeteringResult> future = camera.getCameraControl().startFocusAndMetering(action);
444
526
 
445
- // Add callback to handle the result
527
+ // Add callback to handle the result with enhanced focus maintenance
446
528
  future.addListener(new Runnable() {
447
529
  @Override
448
530
  public void run() {
@@ -461,6 +543,11 @@ public class CameraPreviewPlugin extends Plugin {
461
543
  response.put("x", x);
462
544
  response.put("y", y);
463
545
 
546
+ // If manual focus was successful, maintain it with a follow-up action
547
+ if (result.isFocusSuccessful()) {
548
+ maintainFocusAtPoint(previewX, previewY);
549
+ }
550
+
464
551
  call.resolve(response);
465
552
  } catch (Exception e) {
466
553
  Log.e("Camera", "Focus operation failed", e);
@@ -477,6 +564,51 @@ public class CameraPreviewPlugin extends Plugin {
477
564
  });
478
565
  }
479
566
 
567
+ /**
568
+ * Maintain focus at a specific point with repeated focus actions for stability
569
+ */
570
+ private void maintainFocusAtPoint(float previewX, float previewY) {
571
+ if (camera == null || previewView == null) return;
572
+
573
+ // Use a separate executor for focus maintenance
574
+ ExecutorService focusMaintainExecutor = Executors.newSingleThreadExecutor();
575
+
576
+ focusMaintainExecutor.execute(new Runnable() {
577
+ @Override
578
+ public void run() {
579
+ try {
580
+ // Maintain focus for 10 seconds with periodic refocus
581
+ for (int i = 0; i < 5; i++) {
582
+ Thread.sleep(2000); // Wait 2 seconds between focus actions
583
+
584
+ getActivity().runOnUiThread(new Runnable() {
585
+ @Override
586
+ public void run() {
587
+ try {
588
+ if (camera != null && camera.getCameraInfo().getCameraState().getValue().getType() == CameraState.Type.OPEN) {
589
+ MeteringPointFactory factory = previewView.getMeteringPointFactory();
590
+ MeteringPoint maintainPoint = factory.createPoint(previewX, previewY);
591
+
592
+ FocusMeteringAction maintainAction = new FocusMeteringAction.Builder(maintainPoint)
593
+ .setAutoCancelDuration(3, TimeUnit.SECONDS)
594
+ .build();
595
+
596
+ camera.getCameraControl().startFocusAndMetering(maintainAction);
597
+ Log.d("Camera", "Maintaining focus at tapped point");
598
+ }
599
+ } catch (Exception e) {
600
+ Log.d("Camera", "Focus maintenance failed: " + e.getMessage());
601
+ }
602
+ }
603
+ });
604
+ }
605
+ } catch (InterruptedException e) {
606
+ Log.d("Camera", "Focus maintenance interrupted");
607
+ }
608
+ }
609
+ });
610
+ }
611
+
480
612
  @PluginMethod
481
613
  public void setAutoFocusMode(PluginCall call) {
482
614
  if (camera == null) {
@@ -488,12 +620,17 @@ public class CameraPreviewPlugin extends Plugin {
488
620
  @Override
489
621
  public void run() {
490
622
  try {
491
- String mode = call.getString("mode", "auto");
623
+ String mode = call.getString("mode", "continuous");
624
+ boolean enableFastTransitions = call.getBoolean("enableFastTransitions", true);
625
+ boolean enableAdaptiveFocus = call.getBoolean("enableAdaptiveFocus", true);
492
626
 
493
627
  switch (mode.toLowerCase()) {
494
628
  case "auto":
495
- // Default auto-focus behavior (continuous)
496
- // CameraX handles this automatically
629
+ // Default auto-focus behavior with optimization
630
+ if (enableFastTransitions) {
631
+ // Reset focus to enable faster transitions
632
+ camera.getCameraControl().cancelFocusAndMetering();
633
+ }
497
634
  break;
498
635
  case "manual":
499
636
  // For manual focus, we would need to disable auto-focus
@@ -501,7 +638,35 @@ public class CameraPreviewPlugin extends Plugin {
501
638
  Log.w("Camera", "Manual focus mode not fully supported in CameraX");
502
639
  break;
503
640
  case "continuous":
504
- // This is the default behavior in CameraX
641
+ // Enhanced continuous focus mode with adaptive focusing
642
+ if (enableFastTransitions) {
643
+ // Cancel and restart for faster focus transitions
644
+ camera.getCameraControl().cancelFocusAndMetering();
645
+ }
646
+ if (enableAdaptiveFocus) {
647
+ // Start adaptive continuous focus for better near/far transitions
648
+ startAdaptiveContinuousFocus();
649
+ }
650
+ break;
651
+ case "macro":
652
+ // Optimized for close-up focusing
653
+ Log.i("Camera", "Macro focus mode - optimized for close distances");
654
+ break;
655
+ case "infinity":
656
+ // Optimized for far distance focusing
657
+ // Focus at center point with infinity bias
658
+ if (previewView != null) {
659
+ MeteringPointFactory factory = previewView.getMeteringPointFactory();
660
+ float centerX = previewView.getWidth() / 2.0f;
661
+ float centerY = previewView.getHeight() / 2.0f;
662
+ MeteringPoint centerPoint = factory.createPoint(centerX, centerY);
663
+
664
+ FocusMeteringAction infinityAction = new FocusMeteringAction.Builder(centerPoint)
665
+ .setAutoCancelDuration(1, TimeUnit.SECONDS)
666
+ .build();
667
+
668
+ camera.getCameraControl().startFocusAndMetering(infinityAction);
669
+ }
505
670
  break;
506
671
  default:
507
672
  call.reject("Unsupported focus mode: " + mode);
@@ -511,6 +676,8 @@ public class CameraPreviewPlugin extends Plugin {
511
676
  JSObject result = new JSObject();
512
677
  result.put("success", true);
513
678
  result.put("mode", mode);
679
+ result.put("enableFastTransitions", enableFastTransitions);
680
+ result.put("enableAdaptiveFocus", enableAdaptiveFocus);
514
681
  call.resolve(result);
515
682
  } catch (Exception e) {
516
683
  call.reject("Error setting auto focus mode: " + e.getMessage());
@@ -519,6 +686,70 @@ public class CameraPreviewPlugin extends Plugin {
519
686
  });
520
687
  }
521
688
 
689
+ /**
690
+ * Start adaptive continuous focus for better handling of near/far object transitions
691
+ */
692
+ private void startAdaptiveContinuousFocus() {
693
+ if (camera == null || previewView == null) return;
694
+
695
+ ExecutorService adaptiveFocusExecutor = Executors.newSingleThreadExecutor();
696
+
697
+ adaptiveFocusExecutor.execute(new Runnable() {
698
+ @Override
699
+ public void run() {
700
+ try {
701
+ // Create multiple focus points for better scene coverage
702
+ float[] focusPoints = {
703
+ 0.3f, 0.3f, // Top-left quadrant
704
+ 0.7f, 0.3f, // Top-right quadrant
705
+ 0.5f, 0.5f, // Center
706
+ 0.3f, 0.7f, // Bottom-left quadrant
707
+ 0.7f, 0.7f // Bottom-right quadrant
708
+ };
709
+
710
+ int pointIndex = 0;
711
+
712
+ while (camera != null && camera.getCameraInfo().getCameraState().getValue().getType() == CameraState.Type.OPEN) {
713
+ Thread.sleep(1500); // Focus check every 1.5 seconds
714
+
715
+ final int currentPointIndex = pointIndex;
716
+
717
+ getActivity().runOnUiThread(new Runnable() {
718
+ @Override
719
+ public void run() {
720
+ try {
721
+ if (camera != null && previewView != null) {
722
+ MeteringPointFactory factory = previewView.getMeteringPointFactory();
723
+
724
+ // Use current focus point from the array
725
+ float x = focusPoints[currentPointIndex * 2] * previewView.getWidth();
726
+ float y = focusPoints[currentPointIndex * 2 + 1] * previewView.getHeight();
727
+
728
+ MeteringPoint adaptivePoint = factory.createPoint(x, y);
729
+
730
+ FocusMeteringAction adaptiveAction = new FocusMeteringAction.Builder(adaptivePoint)
731
+ .setAutoCancelDuration(2, TimeUnit.SECONDS)
732
+ .build();
733
+
734
+ camera.getCameraControl().startFocusAndMetering(adaptiveAction);
735
+ Log.d("Camera", "Adaptive focus at point: " + (currentPointIndex + 1));
736
+ }
737
+ } catch (Exception e) {
738
+ Log.d("Camera", "Adaptive focus failed: " + e.getMessage());
739
+ }
740
+ }
741
+ });
742
+
743
+ // Cycle through focus points
744
+ pointIndex = (pointIndex + 1) % (focusPoints.length / 2);
745
+ }
746
+ } catch (InterruptedException e) {
747
+ Log.d("Camera", "Adaptive continuous focus stopped");
748
+ }
749
+ }
750
+ });
751
+ }
752
+
522
753
  @PluginMethod
523
754
  public void resetFocus(PluginCall call) {
524
755
  if (camera == null) {
@@ -533,8 +764,28 @@ public class CameraPreviewPlugin extends Plugin {
533
764
  // Cancel any ongoing focus operations
534
765
  camera.getCameraControl().cancelFocusAndMetering();
535
766
 
767
+ // Restart enhanced continuous autofocus for better stability
768
+ boolean restartContinuous = call.getBoolean("restartContinuous", true);
769
+ if (restartContinuous && previewView != null) {
770
+ // Set focus to center of screen to restart continuous AF with improved settings
771
+ MeteringPointFactory factory = previewView.getMeteringPointFactory();
772
+ float centerX = previewView.getWidth() / 2.0f;
773
+ float centerY = previewView.getHeight() / 2.0f;
774
+ MeteringPoint centerPoint = factory.createPoint(centerX, centerY);
775
+
776
+ FocusMeteringAction restartAction = new FocusMeteringAction.Builder(centerPoint)
777
+ .setAutoCancelDuration(5, TimeUnit.SECONDS) // Increased duration for stability
778
+ .build();
779
+
780
+ camera.getCameraControl().startFocusAndMetering(restartAction);
781
+
782
+ // Restart the continuous auto-focus monitoring
783
+ startContinuousAutoFocus();
784
+ }
785
+
536
786
  JSObject result = new JSObject();
537
787
  result.put("success", true);
788
+ result.put("restartedContinuous", restartContinuous);
538
789
  call.resolve(result);
539
790
  } catch (Exception e) {
540
791
  call.reject("Error resetting focus: " + e.getMessage());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-plugin-camera-forked",
3
- "version": "3.0.12",
3
+ "version": "3.0.13",
4
4
  "description": "A capacitor camera plugin - A custom Capacitor camera plugin with additional features.",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",