From 7928bc1e3d43a6a6f9fb1e9f2f68e6e97ff87bb4 Mon Sep 17 00:00:00 2001 From: Jothiswaran Palaniappan Date: Thu, 10 Apr 2025 13:08:12 +0530 Subject: [PATCH] Added native focus ring for Android and iOS in setFocusModeWithFallback --- android/build.gradle | 5 +- .../camera/preview/CameraActivity.java | 116 +++++++++++++++++- android/src/main/res/drawable/focus_ring.xml | 18 +++ src/definitions.ts | 2 + 4 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 android/src/main/res/drawable/focus_ring.xml diff --git a/android/build.gradle b/android/build.gradle index 6b38b18a..f1ec30d2 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -7,12 +7,15 @@ ext { } buildscript { + ext { + agp_version = '8.2.2' + } repositories { mavenCentral() google() } dependencies { - classpath 'com.android.tools.build:gradle:8.7.2' + classpath "com.android.tools.build:gradle:$agp_version" } } diff --git a/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java b/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java index 257df8f1..19f2129e 100644 --- a/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java +++ b/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java @@ -20,6 +20,7 @@ import android.media.CamcorderProfile; import android.media.MediaRecorder; import android.os.Bundle; +import android.os.Handler; import android.util.Base64; import android.util.DisplayMetrics; import android.util.Log; @@ -45,6 +46,8 @@ import java.util.Arrays; import java.util.List; import java.util.UUID; +import android.widget.ImageView; +import android.widget.Toast; public class CameraActivity extends Fragment { @@ -105,7 +108,7 @@ private enum RecordingState { public int height; public int x; public int y; - + private ImageView focusRingView; public void setEventListener(CameraPreviewListener listener) { eventListener = listener; } @@ -307,7 +310,6 @@ private void handleZoom(MotionEvent event, Camera.Parameters params) { } ); } - private void setDefaultCameraId() { // Find the total number of cameras available numberOfCameras = Camera.getNumberOfCameras(); @@ -982,7 +984,7 @@ public void muteStream(boolean mute, Activity activity) { int direction = mute ? audioManager.ADJUST_MUTE : audioManager.ADJUST_UNMUTE; } - public void setFocusArea(final int pointX, final int pointY, final Camera.AutoFocusCallback callback) { + /*public void setFocusArea(final int pointX, final int pointY, final Camera.AutoFocusCallback callback) { if (mCamera != null) { mCamera.cancelAutoFocus(); @@ -1005,8 +1007,116 @@ public void setFocusArea(final int pointX, final int pointY, final Camera.AutoFo callback.onAutoFocus(false, this.mCamera); } } + }*/ + public void setFocusArea(final int pointX, final int pointY, final Camera.AutoFocusCallback callback) { + + if (mCamera != null) { + CharSequence text ; + int duration; + + Toast toast ; + mCamera.cancelAutoFocus(); + + Camera.Parameters parameters = mCamera.getParameters(); + if (parameters.getMaxNumFocusAreas() > 0) { + Rect focusRect = calculateTapArea(pointX, pointY,1.5f); + parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); + parameters.setFocusAreas(Arrays.asList(new Camera.Area(focusRect, 1000))); + + if (parameters.getMaxNumMeteringAreas() > 0) { + parameters.setMeteringAreas(Arrays.asList(new Camera.Area(focusRect, 1000))); + } + + try { + setCameraParameters(parameters); + + // Show visual indicator (UI Overlay) + showFocusIndicator(pointX, pointY); + + // Trigger autofocus + mCamera.autoFocus(new Camera.AutoFocusCallback() { + @Override + public void onAutoFocus(boolean success, Camera camera) { + if (success) { + Log.d(TAG, "Tap-to-Focus successful"); + + // Auto-reset focus mode to CONTINUOUS_PICTURE after 3 seconds + new Handler().postDelayed(() -> { + Camera.Parameters resetParams = mCamera.getParameters(); + resetParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + setCameraParameters(resetParams); + }, 500); + } else { + Log.d(TAG, "Tap-to-Focus failed"); + } + callback.onAutoFocus(success, camera); + } + }); + + } catch (Exception e) { + Log.e(TAG, "Tap-to-focus failed: " + e.getMessage(), e); + callback.onAutoFocus(false, this.mCamera); + } + } else { + /*text = "Device does not support focus areas!"; + duration = Toast.LENGTH_SHORT; + + toast = Toast.makeText(getActivity(), text, duration); + toast.show(); + Log.d(TAG, "Device does not support focus areas");*/ + } + }else{ + /*CharSequence text = "Camera not available!"; + int duration = Toast.LENGTH_SHORT; + + Toast toast = Toast.makeText(getActivity(), text, duration); + toast.show();*/ + } } + private void showFocusIndicator(final int x, final int y) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + // Remove previous focus ring (if any) + if (focusRingView != null) { + frameContainerLayout.removeView(focusRingView); + } + + // Create a new ImageView for the focus ring + focusRingView = new ImageView(getActivity()); + + // Get focus ring drawable dynamically + int focusRingId = getResources().getIdentifier("focus_ring", "drawable", appResourcesPackage); + + + //Toast.makeText(getActivity(),focusRingId,Toast.LENGTH_SHORT).show(); + focusRingView.setImageResource(focusRingId); + + // Set size of focus ring (adjust if needed) + int focusSize = 200; + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(focusSize, focusSize); + params.leftMargin = x - (focusSize / 2); + params.topMargin = y - (focusSize / 2); + focusRingView.setLayoutParams(params); + + // Add focus ring to the camera preview layout + frameContainerLayout.addView(focusRingView); + + // Animate: Fade out and remove after 1 second + focusRingView.animate() + .alpha(0f) + .setDuration(800) + .withEndAction(new Runnable() { + @Override + public void run() { + frameContainerLayout.removeView(focusRingView); + } + }) + .start(); + } + }); + } private Rect calculateTapArea(float x, float y, float coefficient) { if (x < 100) { x = 100; diff --git a/android/src/main/res/drawable/focus_ring.xml b/android/src/main/res/drawable/focus_ring.xml new file mode 100644 index 00000000..994053eb --- /dev/null +++ b/android/src/main/res/drawable/focus_ring.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/definitions.ts b/src/definitions.ts index 5b1e9bd6..a510c165 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -34,6 +34,8 @@ export interface CameraPreviewOptions { enableOpacity?: boolean; /** Defaults to false - Android only. Set if camera preview will support pinch to zoom. */ enableZoom?: boolean; + /** Defaults to false - Android only. Set if camera preview will support tap to focus. */ + tapToFocus?: boolean; } export interface CameraPreviewPictureOptions { /** The picture height, optional, default 0 (Device default) */