@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,77 @@
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.cpm.india.cameraai"
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 21
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
ndk {
|
||||
abiFilters.add("armeabi-v7a")
|
||||
abiFilters.add("arm64-v8a")
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
// compileOptions {
|
||||
// sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
// targetCompatibility = JavaVersion.VERSION_1_8
|
||||
// }
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
kotlinOptions {
|
||||
// jvmTarget = "1.8"
|
||||
jvmTarget = "17"
|
||||
// jvmToolchain(17) // Set this
|
||||
}
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
//noinspection UseTomlInstead
|
||||
implementation ("androidx.core:core-ktx:1.0.2")
|
||||
implementation ("androidx.appcompat:appcompat:1.3.1")
|
||||
implementation ("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||
implementation ("com.google.android.material:material:1.4.0")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.2.1")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
|
||||
///camerax
|
||||
val camerax_version = "1.1.0-beta02"
|
||||
|
||||
// val camerax_version = "1.5.0-alpha01"
|
||||
implementation ("androidx.camera:camera-core:$camerax_version")
|
||||
implementation ("androidx.camera:camera-camera2:$camerax_version")
|
||||
implementation ("androidx.camera:camera-lifecycle:$camerax_version")
|
||||
implementation ("androidx.camera:camera-view:$camerax_version")
|
||||
///for alert
|
||||
//implementation ("org.jetbrains.anko:anko-common:0.10.4")
|
||||
//for toast msg
|
||||
implementation ("com.github.GrenderG:Toasty:1.4.2")
|
||||
// mlkit face detection & gson
|
||||
implementation ("com.google.mlkit:face-detection:16.1.7")
|
||||
//google gson
|
||||
implementation ("com.google.code.gson:gson:2.10.1")
|
||||
implementation("org.opencv:opencv:4.9.0")
|
||||
implementation ("androidx.activity:activity-ktx:1.8.0")
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.cpm.india.cameraai
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.cpm.india.cameraai.test", appContext.packageName)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
tools:ignore="ScopedStorage" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
tools:ignore="ScopedStorage" />
|
||||
<uses-feature android:name="android.hardware.camera.any" />
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_CAMERA" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera.autofocus"
|
||||
android:required="false" />
|
||||
|
||||
|
||||
<application
|
||||
android:supportsRtl="true"
|
||||
android:allowBackup="false"
|
||||
tools:replace="android:allowBackup">
|
||||
|
||||
<activity
|
||||
android:name=".camera.CameraActivity"
|
||||
android:screenOrientation="portrait"
|
||||
tools:ignore="DiscouragedApi,LockedOrientationActivity"
|
||||
android:exported="false" />
|
||||
|
||||
<activity
|
||||
android:name=".preview.PreviewActivity"
|
||||
android:screenOrientation="portrait"
|
||||
tools:ignore="DiscouragedApi,LockedOrientationActivity"
|
||||
android:exported="false" />
|
||||
|
||||
|
||||
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,421 @@
|
||||
package com.cpm.india.cameraai.camera
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.ContentValues.TAG
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.animation.AlphaAnimation
|
||||
import android.view.animation.Animation
|
||||
//import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.camera.core.CameraSelector
|
||||
import androidx.camera.core.ExperimentalGetImage
|
||||
import androidx.camera.core.ImageAnalysis
|
||||
import androidx.camera.core.ImageCapture
|
||||
import androidx.camera.core.ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY
|
||||
import androidx.camera.core.ImageCapture.FLASH_MODE_AUTO
|
||||
import androidx.camera.core.ImageCaptureException
|
||||
import androidx.camera.core.ImageProxy
|
||||
import androidx.camera.core.Preview
|
||||
import androidx.camera.lifecycle.ProcessCameraProvider
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import com.cpm.india.cameraai.R
|
||||
import com.cpm.india.cameraai.databinding.ActivityCameraBinding
|
||||
import com.cpm.india.cameraai.preview.PreviewActivity
|
||||
import com.cpm.india.cameraai.utils.GetProperImageRotation.checkBlinkAndMovement
|
||||
import com.cpm.india.cameraai.utils.Utils.calculateBrightness
|
||||
import com.cpm.india.cameraai.utils.Utils.checkBlurriness
|
||||
import com.cpm.india.cameraai.utils.Utils.eyeBlink
|
||||
import com.cpm.india.cameraai.utils.Utils.isFaceTooFar
|
||||
import com.cpm.india.cameraai.utils.Utils.isValidHumanFace
|
||||
import com.google.mlkit.vision.common.InputImage
|
||||
import com.google.mlkit.vision.face.Face
|
||||
import com.google.mlkit.vision.face.FaceDetection
|
||||
import com.google.mlkit.vision.face.FaceDetectorOptions
|
||||
import com.google.mlkit.vision.face.FaceLandmark
|
||||
//import org.jetbrains.anko.toast
|
||||
import android.widget.Toast
|
||||
import org.opencv.android.OpenCVLoader
|
||||
import java.io.File
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
class CameraActivity : AppCompatActivity() {
|
||||
private var imageCapture: ImageCapture? = null
|
||||
private lateinit var cameraExecutor: ExecutorService
|
||||
private lateinit var binding: ActivityCameraBinding
|
||||
private var flipX = true
|
||||
private var focusFlag = 0
|
||||
var cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA
|
||||
private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
|
||||
private val REQUEST_CODE_PERMISSIONS = 10
|
||||
private var doubleBackToExitPressedOnce = false
|
||||
private var mainThreadIsStopped: Boolean = true
|
||||
private var parameterThread: Thread? = null
|
||||
private var pictureThread: Thread? = null
|
||||
|
||||
private var filePath: String? = null
|
||||
private var isGrid: Boolean? = false
|
||||
private var isCheckFace: Boolean? = true
|
||||
private var isFacingFront: Boolean? = true
|
||||
private var isFlash = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
// enableEdgeToEdge()
|
||||
binding = ActivityCameraBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets ->
|
||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||
insets
|
||||
}
|
||||
if (!OpenCVLoader.initLocal()) {
|
||||
Log.e("OpenCv", "OpenCV initialization failed")
|
||||
} else {
|
||||
Log.d("OpenCv", "OpenCV initialization succeeded")
|
||||
}
|
||||
eyeBlink = false
|
||||
filePath = intent.getStringExtra("filePath")
|
||||
isGrid = intent.getBooleanExtra("isGrid", false)
|
||||
isCheckFace = intent.getBooleanExtra("isCheckFace", false)
|
||||
isFacingFront = intent.getBooleanExtra("isFacingFront", true)
|
||||
Log.e("filePath", filePath!!)
|
||||
if (!isFacingFront!!) cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
|
||||
if (isCheckFace!!) binding.capturebtnCameraActivity.visibility = View.INVISIBLE
|
||||
switchCamera()
|
||||
cameraExecutor = Executors.newSingleThreadExecutor()
|
||||
if (allPermissionsGranted()) {
|
||||
startCamera()
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(
|
||||
this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS
|
||||
)
|
||||
}
|
||||
focusingContinuous()
|
||||
requestPermissionsforApp()
|
||||
calledOnClick()
|
||||
}
|
||||
|
||||
private fun focusingContinuous() {
|
||||
focusFlag = 1
|
||||
this@CameraActivity.runOnUiThread {
|
||||
runOnUiThread {
|
||||
val anim = AlphaAnimation(0.0f, 1.0f)
|
||||
anim.duration = 10//You can manage the time of the blink with this parameter
|
||||
anim.startOffset = 300
|
||||
anim.repeatMode = Animation.REVERSE
|
||||
anim.repeatCount = Animation.INFINITE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun calledOnClick() {
|
||||
Log.d("Jeevanpclick", filePath.toString())
|
||||
binding.capturebtnCameraActivity.setOnClickListener {
|
||||
val outputOptions = ImageCapture.OutputFileOptions.Builder(File(filePath!!)).build()
|
||||
mainThreadIsStopped = true
|
||||
imageCapture?.takePicture(
|
||||
outputOptions,
|
||||
ContextCompat.getMainExecutor(this),
|
||||
object : ImageCapture.OnImageSavedCallback {
|
||||
override fun onError(exception: ImageCaptureException) {
|
||||
exception.printStackTrace()
|
||||
}
|
||||
|
||||
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
|
||||
mainThreadIsStopped = true
|
||||
pictureThread = thread(start = true) {
|
||||
val savedUri = outputFileResults.savedUri
|
||||
Log.d("Jeevanp", savedUri.toString())
|
||||
val bitmap = BitmapFactory.decodeFile(savedUri?.path)
|
||||
val openCvResult = checkBlurriness(bitmap)
|
||||
val brightnessResult = calculateBrightness(bitmap)
|
||||
if (openCvResult == 1 && brightnessResult.absoluteValue > 0.20) {
|
||||
Log.d("Jeevanp", "1")
|
||||
val intent =
|
||||
Intent(this@CameraActivity, PreviewActivity::class.java)
|
||||
intent.putExtra("photoUri", File(filePath!!).absolutePath)
|
||||
resultLauncher.launch(intent)
|
||||
} else {
|
||||
if (openCvResult != 1 && brightnessResult.absoluteValue <= 0.32) {
|
||||
Log.d("Jeevanp", "2")
|
||||
// runOnUiThread {
|
||||
// toast("Image is blurry and dark. Please try again.")
|
||||
// }
|
||||
|
||||
runOnUiThread {
|
||||
Toast.makeText(applicationContext, "Image is blurry. and dark. Please try again", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
|
||||
|
||||
} else if (brightnessResult.absoluteValue <= 0.32) {
|
||||
Log.d("Jeevanp", "3")
|
||||
runOnUiThread {
|
||||
// toast("Image is dark. Please try again.")
|
||||
Toast.makeText(applicationContext, "Image is dark. Please try again.", Toast.LENGTH_SHORT).show()
|
||||
|
||||
}
|
||||
} else {
|
||||
Log.d("Jeevanp", "4")
|
||||
runOnUiThread {
|
||||
// toast("Image is blurry. Please try again.")
|
||||
Toast.makeText(applicationContext, "Image is blurry. Please try again.", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private var resultLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
// There are no request codes
|
||||
val data: Intent? = result.data
|
||||
if (data != null) {
|
||||
val intent = Intent()
|
||||
intent.putExtra("filePath", data.getStringExtra("filePath").toString())
|
||||
setResult(RESULT_OK, intent)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun switchCamera() {
|
||||
binding.switchCamera.setOnClickListener {
|
||||
if (cameraSelector == CameraSelector.DEFAULT_BACK_CAMERA) {
|
||||
cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA
|
||||
flipX = true
|
||||
} else {
|
||||
cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
|
||||
flipX = false
|
||||
}
|
||||
startCamera()
|
||||
}
|
||||
}
|
||||
|
||||
private fun startCamera() {
|
||||
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
|
||||
cameraProviderFuture.addListener({
|
||||
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
|
||||
val preview = Preview.Builder().build()
|
||||
.also {
|
||||
it.setSurfaceProvider(binding.texture.surfaceProvider)
|
||||
//it.surfaceProvider = binding.texture.surfaceProvider
|
||||
}
|
||||
imageCapture = ImageCapture.Builder()
|
||||
.setCaptureMode(CAPTURE_MODE_MAXIMIZE_QUALITY)
|
||||
.setFlashMode(FLASH_MODE_AUTO)
|
||||
.setJpegQuality(100)
|
||||
.build()
|
||||
|
||||
val imageAnalyzer = ImageAnalysis.Builder()
|
||||
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
||||
.build()
|
||||
.also {
|
||||
it.setAnalyzer(
|
||||
cameraExecutor,
|
||||
LuminosityAnalyzer(binding, isCheckFace!!, context = this)
|
||||
)
|
||||
}
|
||||
try {
|
||||
cameraProvider.unbindAll()
|
||||
val cam = cameraProvider.bindToLifecycle(
|
||||
this, cameraSelector, preview, imageCapture, imageAnalyzer
|
||||
)
|
||||
binding.ivFlash.setOnClickListener {
|
||||
if (cam.cameraInfo.hasFlashUnit()) {
|
||||
if (!isFlash) {
|
||||
isFlash = true
|
||||
cam.cameraControl.enableTorch(true) // or false
|
||||
binding.ivFlash.setImageResource(R.mipmap.ic_flash_on_white_24dp)
|
||||
} else {
|
||||
isFlash = false
|
||||
cam.cameraControl.enableTorch(false) // or false
|
||||
binding.ivFlash.setImageResource(R.mipmap.ic_flash_off_white_24dp)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (exc: Exception) {
|
||||
Log.e(TAG, "Use case binding failed", exc)
|
||||
}
|
||||
}, ContextCompat.getMainExecutor(this))
|
||||
}
|
||||
|
||||
private fun requestPermissionsforApp() {
|
||||
ActivityCompat.requestPermissions(
|
||||
this@CameraActivity,
|
||||
arrayOf(Manifest.permission.CAMERA),
|
||||
2
|
||||
)
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int, permissions: Array<String>, grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (requestCode == REQUEST_CODE_PERMISSIONS) {
|
||||
if (allPermissionsGranted()) {
|
||||
startCamera()
|
||||
} else {
|
||||
runOnUiThread {
|
||||
// toast("Permissions not granted by the user.")
|
||||
Toast.makeText(applicationContext, "Permissions not granted by the user.", Toast.LENGTH_SHORT).show()
|
||||
|
||||
}
|
||||
this@CameraActivity.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
|
||||
ContextCompat.checkSelfPermission(
|
||||
baseContext, it
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
public class LuminosityAnalyzer(
|
||||
val binding: ActivityCameraBinding,
|
||||
val isCheckFace: Boolean,
|
||||
val context: Context
|
||||
) :
|
||||
ImageAnalysis.Analyzer {
|
||||
private fun ByteBuffer.toByteArray(): ByteArray {
|
||||
rewind() // Rewind the buffer to zero
|
||||
val data = ByteArray(remaining())
|
||||
get(data) // Copy the buffer into a byte array
|
||||
return data // Return the byte array
|
||||
}
|
||||
|
||||
@androidx.annotation.OptIn(ExperimentalGetImage::class)
|
||||
override fun analyze(image: ImageProxy) {
|
||||
val inputImage = InputImage.fromMediaImage(
|
||||
image.image!!,
|
||||
image.imageInfo.rotationDegrees
|
||||
)
|
||||
val options = FaceDetectorOptions.Builder()
|
||||
.setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE)
|
||||
.setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL) // Detect landmarks (eyes, mouth, etc.)
|
||||
.setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL) // Enable face classification (e.g., smiling, eyes open)
|
||||
.setMinFaceSize(0.1f) // Detect smaller faces in the image
|
||||
.enableTracking() // Track faces across frames
|
||||
.build()
|
||||
val faceDetector = FaceDetection.getClient(options)
|
||||
faceDetector.process(inputImage)
|
||||
.addOnSuccessListener { faces: List<Face?>? ->
|
||||
onSuccessListener(
|
||||
faces,
|
||||
inputImage,
|
||||
binding,
|
||||
isCheckFace,
|
||||
context
|
||||
)
|
||||
}.addOnFailureListener {
|
||||
}.addOnCompleteListener { image.close() }
|
||||
}
|
||||
|
||||
@SuppressLint("ResourceType", "UseCompatLoadingForDrawables")
|
||||
fun onSuccessListener(
|
||||
faces: List<Face?>?,
|
||||
inputImage: InputImage,
|
||||
binding: ActivityCameraBinding,
|
||||
isCheckFace: Boolean,
|
||||
context: Context
|
||||
) {
|
||||
if (isCheckFace) {
|
||||
if (!faces.isNullOrEmpty()) {
|
||||
for (face in faces) {
|
||||
val boundingBox = face?.boundingBox
|
||||
// Ensure detected face meets conditions that typically indicate a human face
|
||||
val leftEye = face?.getLandmark(FaceLandmark.LEFT_EYE)
|
||||
val rightEye = face?.getLandmark(FaceLandmark.RIGHT_EYE)
|
||||
val nose = face?.getLandmark(FaceLandmark.NOSE_BASE)
|
||||
val mouthLeft = face?.getLandmark(FaceLandmark.MOUTH_LEFT)
|
||||
val mouthRight = face?.getLandmark(FaceLandmark.MOUTH_RIGHT)
|
||||
if (checkBlinkAndMovement(face!!)) {
|
||||
eyeBlink = true
|
||||
}
|
||||
// Check if the face is too far based on the bounding box size
|
||||
Log.e("eyeBlink", "$eyeBlink")
|
||||
// Example condition: only consider it a human face if the eyes and mouth probabilities are detected
|
||||
if (leftEye != null && rightEye != null && nose != null && mouthLeft != null && mouthRight != null) {
|
||||
if (isValidHumanFace(face) && !isFaceTooFar(boundingBox) && eyeBlink) {
|
||||
Log.e("facedata", "Face detected")
|
||||
binding.tvImageBlurr.setText(R.string.face_detected)
|
||||
binding.capturebtnCameraActivity.visibility = View.VISIBLE
|
||||
} else {
|
||||
Log.e("facedata", "No Face detected")
|
||||
binding.tvImageBlurr.setText(R.string.no_face_detected)
|
||||
binding.capturebtnCameraActivity.visibility = View.INVISIBLE
|
||||
}
|
||||
} else {
|
||||
Log.e("facedata", "No Face detected")
|
||||
binding.tvImageBlurr.setText(R.string.no_face_detected)
|
||||
binding.capturebtnCameraActivity.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.e("facedata", "No Face detected")
|
||||
binding.tvImageBlurr.setText(R.string.no_face_detected)
|
||||
binding.capturebtnCameraActivity.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
focusFlag = 0
|
||||
eyeBlink = false
|
||||
mainThreadIsStopped = false
|
||||
binding.capturebtnCameraActivity.isEnabled = true
|
||||
parameterThread = thread(start = true) {
|
||||
this@CameraActivity.runOnUiThread {
|
||||
binding.infoPanel.text = "Please stand in a well lit area"
|
||||
}
|
||||
Thread.sleep(1000)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
mainThreadIsStopped = true
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
Runtime.getRuntime().gc()
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (doubleBackToExitPressedOnce) {
|
||||
super.onBackPressed()
|
||||
return
|
||||
}
|
||||
this.doubleBackToExitPressedOnce = true
|
||||
// toast("Please click BACK again to exit")
|
||||
Toast.makeText(applicationContext, "Please click BACK again to exit", Toast.LENGTH_SHORT).show()
|
||||
Handler().postDelayed({
|
||||
doubleBackToExitPressedOnce = false
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.cpm.india.cameraai.preview
|
||||
import android.content.Intent
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.cpm.india.cameraai.databinding.ActivityPreviewBinding
|
||||
import com.cpm.india.cameraai.utils.GetProperImageRotation
|
||||
import java.io.File
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
class PreviewActivity : AppCompatActivity() {
|
||||
private lateinit var cameraExecutor: ExecutorService
|
||||
private lateinit var binding: ActivityPreviewBinding
|
||||
private var photoUri: String? = null
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityPreviewBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
cameraExecutor = Executors.newSingleThreadExecutor()
|
||||
photoUri = intent.getStringExtra("photoUri")
|
||||
val photoFile = photoUri?.let { File(it) }
|
||||
if (photoUri != null) {
|
||||
Log.d("uridata", photoUri!!)
|
||||
}
|
||||
|
||||
val rotatedImageFile = GetProperImageRotation.getRotatedImageFile(photoFile, photoUri, this)
|
||||
binding.capturedImageView.setImageBitmap(BitmapFactory.decodeFile(rotatedImageFile?.absolutePath))
|
||||
binding.retakeLL.setOnClickListener {
|
||||
finish() // Go back to the camera activity
|
||||
}
|
||||
|
||||
binding.cancelLL.setOnClickListener {
|
||||
deleteImageFile(photoFile!!.absolutePath)
|
||||
finish() // Go back to the camera activity
|
||||
}
|
||||
|
||||
binding.saveLL.setOnClickListener {
|
||||
val intent = Intent()
|
||||
intent.putExtra("filePath", photoUri!!)
|
||||
setResult(RESULT_OK, intent)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
private fun deleteImageFile(filePath: String): Boolean {
|
||||
val file = File(filePath)
|
||||
return if (file.exists()) {
|
||||
val isDeleted = file.delete()
|
||||
if (isDeleted) {
|
||||
Log.d("FileDeletion", "File deleted successfully: $filePath")
|
||||
} else {
|
||||
Log.e("FileDeletion", "File deletion failed: $filePath")
|
||||
}
|
||||
isDeleted
|
||||
} else {
|
||||
Log.e("FileDeletion", "File does not exist: $filePath")
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure to shut down the executor
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
cameraExecutor.shutdown()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.cpm.india.cameraai.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Matrix
|
||||
import android.util.Log
|
||||
import androidx.exifinterface.media.ExifInterface
|
||||
import java.io.BufferedOutputStream
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import com.google.mlkit.vision.face.Face
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
object GetProperImageRotation {
|
||||
fun getRotatedImageFile(photoFile: File?, filePath: String?, context: Context?): File? {
|
||||
val option = BitmapFactory.Options()
|
||||
option.inSampleSize = 4
|
||||
val convertedBitmap: Bitmap =
|
||||
modifyOrientation(
|
||||
BitmapFactory.decodeFile(photoFile!!.absolutePath, option),
|
||||
photoFile.absolutePath, context
|
||||
)
|
||||
return saveImage(convertedBitmap, filePath)
|
||||
|
||||
}
|
||||
|
||||
private fun saveImage(image: Bitmap, filePath: String?): File? {
|
||||
// Get the file object
|
||||
val file = filePath?.let { File(it) }
|
||||
val os = BufferedOutputStream(FileOutputStream(file))
|
||||
image.compress(Bitmap.CompressFormat.JPEG, 100, os)
|
||||
os.close()
|
||||
return file
|
||||
}
|
||||
|
||||
private fun modifyOrientation(
|
||||
bitmap: Bitmap,
|
||||
image_absolute_path: String,
|
||||
context: Context?
|
||||
): Bitmap {
|
||||
val ei = ExifInterface(image_absolute_path)
|
||||
val orientation: Int =
|
||||
ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
|
||||
Log.e("orintation", "" + getScreenOrientation(context))
|
||||
when (orientation) {
|
||||
ExifInterface.ORIENTATION_ROTATE_90 -> {
|
||||
return rotate(bitmap, 90f)
|
||||
}
|
||||
ExifInterface.ORIENTATION_ROTATE_180 -> {
|
||||
return rotate(bitmap, 180f)
|
||||
}
|
||||
|
||||
ExifInterface.ORIENTATION_TRANSVERSE -> {
|
||||
return rotate(bitmap, 270f)
|
||||
}
|
||||
|
||||
ExifInterface.ORIENTATION_ROTATE_270 -> {
|
||||
return rotate(bitmap, 270f)
|
||||
}
|
||||
|
||||
ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> {
|
||||
return flip(bitmap, true, vertical = false)
|
||||
}
|
||||
|
||||
ExifInterface.ORIENTATION_FLIP_VERTICAL -> {
|
||||
return flip(bitmap, false, vertical = true)
|
||||
}
|
||||
|
||||
else -> {
|
||||
return bitmap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun rotate(bitmap: Bitmap, degrees: Float): Bitmap {
|
||||
val matrix = Matrix()
|
||||
matrix.postRotate(degrees)
|
||||
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
|
||||
}
|
||||
|
||||
private fun flip(bitmap: Bitmap, horizontal: Boolean, vertical: Boolean): Bitmap {
|
||||
val matrix = Matrix()
|
||||
matrix.preScale(if (horizontal) (-1f) else 1f, if (vertical) (-1f) else 1f)
|
||||
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true);
|
||||
}
|
||||
|
||||
// Function to check for blink and movement
|
||||
fun checkBlinkAndMovement(face: Face): Boolean {
|
||||
// Step 1: Check blink detection
|
||||
val leftEyeOpenProbability = face.leftEyeOpenProbability ?: -1f
|
||||
val rightEyeOpenProbability = face.rightEyeOpenProbability ?: -1f
|
||||
// If both eyes are open or closed, consider it a blink detection scenario
|
||||
val isBlinking = leftEyeOpenProbability < 0.3 && rightEyeOpenProbability < 0.3
|
||||
// Step 2: Check for facial movement (pose detection)
|
||||
val headEulerAngleX = face.headEulerAngleX // Head tilt up/down
|
||||
val headEulerAngleY = face.headEulerAngleY // Head turn left/right
|
||||
val headEulerAngleZ = face.headEulerAngleZ // Head tilt sideways
|
||||
// If the face poses (angles) change significantly between frames, consider it as movement
|
||||
val isMoving =
|
||||
headEulerAngleX.absoluteValue > 10 || headEulerAngleY.absoluteValue > 10 || headEulerAngleZ.absoluteValue > 10
|
||||
// Return true if either blinking or movement is detected
|
||||
return isBlinking && isMoving
|
||||
}
|
||||
|
||||
fun getScreenOrientation(context: Context?): Int {
|
||||
val configuration = context?.resources!!.configuration
|
||||
// If the configuration returns ORIENTATION_UNDEFINED, manually check width/height
|
||||
if (configuration.orientation == Configuration.ORIENTATION_UNDEFINED) {
|
||||
val displayMetrics = context.resources!!.displayMetrics
|
||||
return if (displayMetrics.widthPixels > displayMetrics.heightPixels) {
|
||||
Configuration.ORIENTATION_LANDSCAPE
|
||||
} else {
|
||||
Configuration.ORIENTATION_PORTRAIT
|
||||
}
|
||||
}
|
||||
|
||||
return configuration.orientation
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package com.cpm.india.cameraai.utils
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.Rect
|
||||
import android.media.Image
|
||||
import android.util.Log
|
||||
import com.google.mlkit.vision.face.Face
|
||||
import org.opencv.android.Utils
|
||||
import org.opencv.core.Core
|
||||
import org.opencv.core.Mat
|
||||
import org.opencv.core.MatOfDouble
|
||||
import org.opencv.imgproc.Imgproc
|
||||
import java.nio.ReadOnlyBufferException
|
||||
import kotlin.experimental.inv
|
||||
|
||||
object Utils {
|
||||
var eyeBlink = false
|
||||
private fun rotateBitmap(bitmap: Bitmap, rotationDegrees: Int, flipX: Boolean): Bitmap {
|
||||
val matrix = Matrix()
|
||||
// Rotate the image back to straight.
|
||||
matrix.postRotate(rotationDegrees.toFloat())
|
||||
// Mirror the image along the X or Y axis.
|
||||
matrix.postScale(if (flipX) -1.0f else 1.0f, 1.0f)
|
||||
val rotatedBitmap =
|
||||
Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
|
||||
// Recycle the old bitmap if it has changed.
|
||||
if (rotatedBitmap != bitmap) {
|
||||
bitmap.recycle()
|
||||
}
|
||||
return rotatedBitmap
|
||||
}
|
||||
private fun YUV_420_888toNV21(image: Image): ByteArray {
|
||||
val width = image.width
|
||||
val height = image.height
|
||||
val ySize = width * height
|
||||
val uvSize = width * height / 4
|
||||
val nv21 = ByteArray(ySize + uvSize * 2)
|
||||
val yBuffer = image.planes[0].buffer // Y
|
||||
val uBuffer = image.planes[1].buffer // U
|
||||
val vBuffer = image.planes[2].buffer // V
|
||||
var rowStride = image.planes[0].rowStride
|
||||
assert(image.planes[0].pixelStride == 1)
|
||||
|
||||
var pos = 0
|
||||
|
||||
if (rowStride == width) { // likely
|
||||
yBuffer[nv21, 0, ySize]
|
||||
pos += ySize
|
||||
} else {
|
||||
var yBufferPos = -rowStride.toLong() // not an actual position
|
||||
while (pos < ySize) {
|
||||
yBufferPos += rowStride.toLong()
|
||||
yBuffer.position(yBufferPos.toInt())
|
||||
yBuffer[nv21, pos, width]
|
||||
pos += width
|
||||
}
|
||||
}
|
||||
|
||||
rowStride = image.planes[2].rowStride
|
||||
val pixelStride = image.planes[2].pixelStride
|
||||
assert(rowStride == image.planes[1].rowStride)
|
||||
assert(pixelStride == image.planes[1].pixelStride)
|
||||
if (pixelStride == 2 && rowStride == width && uBuffer[0] == vBuffer[1]) {
|
||||
// maybe V an U planes overlap as per NV21, which means vBuffer[1] is alias of uBuffer[0]
|
||||
val savePixel = vBuffer[1]
|
||||
try {
|
||||
vBuffer.put(1, savePixel.inv() as Byte)
|
||||
if (uBuffer[0] == savePixel.inv() as Byte) {
|
||||
vBuffer.put(1, savePixel)
|
||||
vBuffer.position(0)
|
||||
uBuffer.position(0)
|
||||
vBuffer[nv21, ySize, 1]
|
||||
uBuffer[nv21, ySize + 1, uBuffer.remaining()]
|
||||
|
||||
return nv21 // shortcut
|
||||
}
|
||||
} catch (ex: ReadOnlyBufferException) {
|
||||
// unfortunately, we cannot check if vBuffer and uBuffer overlap
|
||||
}
|
||||
// unfortunately, the check failed. We must save U and V pixel by pixel
|
||||
vBuffer.put(1, savePixel)
|
||||
}
|
||||
|
||||
// other optimizations could check if (pixelStride == 1) or (pixelStride == 2),
|
||||
// but performance gain would be less significant
|
||||
for (row in 0 until height / 2) {
|
||||
for (col in 0 until width / 2) {
|
||||
val vuPos = col * pixelStride + row * rowStride
|
||||
nv21[pos++] = vBuffer[vuPos]
|
||||
nv21[pos++] = uBuffer[vuPos]
|
||||
}
|
||||
}
|
||||
|
||||
return nv21
|
||||
}
|
||||
private fun getResizedBitmap(bm: Bitmap): Bitmap {
|
||||
val width = bm.width
|
||||
val height = bm.height
|
||||
val scaleWidth = (112f) / width
|
||||
val scaleHeight = (112f) / height
|
||||
// CREATE A MATRIX FOR THE MANIPULATION
|
||||
val matrix = Matrix()
|
||||
// RESIZE THE BIT MAP
|
||||
matrix.postScale(scaleWidth, scaleHeight)
|
||||
// "RECREATE" THE NEW BITMAP
|
||||
val resizedBitmap = Bitmap.createBitmap(
|
||||
bm, 0, 0, width, height, matrix, false
|
||||
)
|
||||
bm.recycle()
|
||||
return resizedBitmap
|
||||
}
|
||||
fun isValidHumanFace(face: Face): Boolean {
|
||||
val boundingBox = face.boundingBox
|
||||
val faceWidth = boundingBox.width()
|
||||
val faceHeight = boundingBox.height()
|
||||
// Check face size or proportions (e.g., width to height ratio)
|
||||
val aspectRatio = faceWidth.toFloat() / faceHeight.toFloat()
|
||||
if (aspectRatio < 0.75 || aspectRatio > 1.3) {
|
||||
return false // Unusual face shape, likely not a human face
|
||||
}
|
||||
// Additional checks can be added here
|
||||
return true
|
||||
}
|
||||
|
||||
// Function to check if the face is too far based on bounding box size
|
||||
fun isFaceTooFar(boundingBox: Rect?): Boolean {
|
||||
// Use width or height of the bounding box to determine if the face is too far
|
||||
val faceWidth = boundingBox?.width()
|
||||
// Set a threshold for face width (this value will depend on your camera and testing)
|
||||
val farThreshold = 100 // Example threshold, adjust based on testing
|
||||
// If the face width is smaller than the threshold, consider it too far
|
||||
return faceWidth!! < farThreshold
|
||||
}
|
||||
|
||||
fun checkBlurriness(result: Bitmap): Int {
|
||||
val destination = Mat()
|
||||
val image = Mat()
|
||||
val matGray = Mat()
|
||||
val std = MatOfDouble()
|
||||
val median = MatOfDouble()
|
||||
Utils.bitmapToMat(result, image)
|
||||
Imgproc.cvtColor(image, matGray, Imgproc.COLOR_BGR2GRAY)
|
||||
Imgproc.Laplacian(matGray, destination, 3)
|
||||
Core.meanStdDev(destination, median, std)
|
||||
val variance = Math.pow(std.get(0, 0)[0], 2.0)
|
||||
Log.i("Variance : ", variance.toString())
|
||||
return if (variance < 10) {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
fun calculateBrightness(bitmap: Bitmap): Float {
|
||||
return calculateBrightnessEstimate(bitmap, 1)
|
||||
}
|
||||
private fun calculateBrightnessEstimate(bitmap: Bitmap, pixelSpacing: Int): Float {
|
||||
var r = 0
|
||||
var g = 0
|
||||
var b = 0
|
||||
val height = bitmap.height
|
||||
val width = bitmap.width
|
||||
var n = 0
|
||||
var lux = 0.0f
|
||||
val pixels = IntArray(width * height)
|
||||
bitmap.getPixels(pixels, 0, width, 0, 0, width, height)
|
||||
var i = 0
|
||||
while (i < pixels.size) {
|
||||
val color = pixels[i]
|
||||
r = Color.red(color)
|
||||
g = Color.green(color)
|
||||
b = Color.blue(color)
|
||||
val luminance = (r * 0.2126f + g * 0.7152f + b * 0.0722f) / 255
|
||||
lux += luminance
|
||||
n++
|
||||
i += pixelSpacing
|
||||
}
|
||||
return lux / n
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512"
|
||||
android:width="512dp"
|
||||
android:height="512dp">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M0 0l512 0 0 512 -512 0z" />
|
||||
<path
|
||||
android:pathData="M512 256A256 256 0 0 1 256 512 256 256 0 0 1 0 256 256 256 0 0 1 256 0 256 256 0 0 1 512 256Z"
|
||||
android:fillColor="#ffffff" />
|
||||
<path
|
||||
android:pathData="M511.5 256A255.5 255.5 0 0 1 256 511.5 255.5 255.5 0 0 1 0.5 256 255.5 255.5 0 0 1 256 0.5 255.5 255.5 0 0 1 511.5 256Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#707070" />
|
||||
<group
|
||||
android:translateX="45"
|
||||
android:translateY="45">
|
||||
<path
|
||||
android:pathData="M422 211A211 211 0 0 1 211 422 211 211 0 0 1 0 211 211 211 0 0 1 211 0 211 211 0 0 1 422 211Z"
|
||||
android:fillColor="#d2d9e0" />
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
@@ -0,0 +1,16 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="@color/white">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M9,12c0,1.66 1.34,3 3,3s3,-1.34 3,-3s-1.34,-3 -3,-3S9,10.34 9,12zM13,12c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1s0.45,-1 1,-1S13,11.45 13,12z"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M8,10V8H5.09C6.47,5.61 9.05,4 12,4c3.72,0 6.85,2.56 7.74,6h2.06c-0.93,-4.56 -4.96,-8 -9.8,-8C8.73,2 5.82,3.58 4,6.01V4H2v6H8z"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M16,14v2h2.91c-1.38,2.39 -3.96,4 -6.91,4c-3.72,0 -6.85,-2.56 -7.74,-6H2.2c0.93,4.56 4.96,8 9.8,8c3.27,0 6.18,-1.58 8,-4.01V20h2v-6H16z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle" >
|
||||
<corners android:radius="75dp" />
|
||||
<solid
|
||||
android:color="#99D2D9E0" />
|
||||
<stroke
|
||||
android:color="#99D2D9E0"
|
||||
android:width="2dp"/>
|
||||
</shape>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<stroke android:color="#FFF" android:width="1dp"/>
|
||||
<corners android:radius="100dp" />
|
||||
</shape>
|
||||
@@ -0,0 +1,149 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".camera.CameraActivity">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="130dp"
|
||||
android:layout_marginBottom="124dp"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toTopOf="@+id/infoPanel"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintVertical_bias="1.0" />
|
||||
|
||||
<androidx.camera.view.PreviewView
|
||||
android:id="@+id/texture"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.0">
|
||||
</androidx.camera.view.PreviewView>
|
||||
|
||||
<Space
|
||||
android:id="@+id/space"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="1dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/capturebtn_camera_activity"
|
||||
app:layout_constraintEnd_toStartOf="@+id/capturebtn_camera_activity"
|
||||
app:layout_constraintTop_toTopOf="@+id/capturebtn_camera_activity" />
|
||||
|
||||
<View
|
||||
android:id="@+id/transparent_layout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="#88676767"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/infoPanel"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="70dp"
|
||||
android:layout_marginEnd="70dp"
|
||||
android:layout_marginBottom="240dp"
|
||||
android:background="@drawable/rounded_corners"
|
||||
android:padding="8dp"
|
||||
android:visibility="invisible"
|
||||
android:text="@string/need_all_green_dots_to_start_taking_pictures"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#80000000"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivFlash"
|
||||
android:layout_width="38dp"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginStart="50dp"
|
||||
android:layout_marginBottom="100dp"
|
||||
android:background="@drawable/roundedcorner"
|
||||
android:src="@mipmap/ic_flash_off_white_24dp"
|
||||
android:textAlignment="center"
|
||||
android:scaleType="centerInside"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/switch_camera"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/capturebtn_camera_activity"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="80dp"
|
||||
android:layout_marginStart="128dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:layout_marginBottom="80dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/camera_capture_button"
|
||||
android:scaleType="centerInside"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/switch_camera"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:srcCompat="@drawable/ic_camera_icon" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guideline"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_percent="0.5" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linearLayout_alpha"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:orientation="vertical"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toTopOf="@+id/infoPanel"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvImageBlurr"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="387dp"
|
||||
android:text="@string/no_face_detected"
|
||||
android:textColor="@color/red"
|
||||
android:textSize="25sp"
|
||||
android:gravity="center"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/texture" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/switch_camera"
|
||||
android:layout_width="38dp"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginBottom="100dp"
|
||||
android:layout_marginEnd="50dp"
|
||||
android:background="@drawable/roundedcorner"
|
||||
android:contentDescription="@string/switch_camera"
|
||||
android:src="@drawable/outline_flip_camera_android_24"
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,103 @@
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:background="@color/black"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/capturedImageView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="?actionBarSize"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:background="@color/black"
|
||||
/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?actionBarSize"
|
||||
android:orientation="horizontal"
|
||||
android:background="@android:color/holo_blue_light"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:weightSum="3">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/cancelLL"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:layout_weight="1"
|
||||
>
|
||||
<ImageView
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:src="@mipmap/close"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/cancelTV"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-condensed-medium"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:textSize="16sp"
|
||||
android:text="Cancel"
|
||||
android:textColor="@color/black"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/retakeLL"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:layout_weight="1"
|
||||
>
|
||||
<ImageView
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:src="@mipmap/retake"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/retakeTV"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:fontFamily="sans-serif-condensed-medium"
|
||||
android:textSize="16sp"
|
||||
android:text="Retake"
|
||||
android:textColor="@color/black"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/saveLL"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:layout_weight="1"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:src="@mipmap/tick"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/doneTV"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:fontFamily="sans-serif-condensed-medium"
|
||||
android:textSize="16sp"
|
||||
android:text="Ok"
|
||||
android:textColor="@color/black" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 306 B |
|
After Width: | Height: | Size: 217 B |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 223 B |
|
After Width: | Height: | Size: 158 B |
|
After Width: | Height: | Size: 345 B |
|
After Width: | Height: | Size: 239 B |
|
After Width: | Height: | Size: 485 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 602 B |
|
After Width: | Height: | Size: 386 B |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
<color name="red">#FF0000</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<resources>
|
||||
<string name="switch_camera">switch camera</string>
|
||||
<string name="face_detected">Face Detected</string>
|
||||
<string name="no_face_detected">No Face Detected!</string>
|
||||
<string name="camera_capture_button">Camera Capture Button</string>
|
||||
<string name="need_all_green_dots_to_start_taking_pictures">Need all green dots to start taking pictures</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.cpm.india.cameraai
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
apply plugin: "com.android.application"
|
||||
apply plugin: "org.jetbrains.kotlin.android"
|
||||
apply plugin: "com.facebook.react"
|
||||
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
|
||||
apply plugin: "com.google.gms.google-services"
|
||||
apply plugin: "com.google.firebase.crashlytics"
|
||||
|
||||
|
||||
react {
|
||||
autolinkLibrariesWithApp()
|
||||
}
|
||||
|
||||
def enableProguardInReleaseBuilds = false
|
||||
def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
|
||||
|
||||
android {
|
||||
namespace "com.performics"
|
||||
compileSdk rootProject.ext.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.performics"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 181
|
||||
versionName "6.9"
|
||||
missingDimensionStrategy 'react-native-camera', 'general'
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
debug {
|
||||
if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) {
|
||||
storeFile file(MYAPP_UPLOAD_STORE_FILE)
|
||||
storePassword MYAPP_UPLOAD_STORE_PASSWORD
|
||||
keyAlias MYAPP_UPLOAD_KEY_ALIAS
|
||||
keyPassword MYAPP_UPLOAD_KEY_PASSWORD
|
||||
}
|
||||
else{
|
||||
storeFile file('debug.keystore')
|
||||
storePassword 'android'
|
||||
keyAlias 'androiddebugkey'
|
||||
keyPassword 'android'
|
||||
}
|
||||
}
|
||||
release {
|
||||
if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) {
|
||||
storeFile file(MYAPP_UPLOAD_STORE_FILE)
|
||||
storePassword MYAPP_UPLOAD_STORE_PASSWORD
|
||||
keyAlias MYAPP_UPLOAD_KEY_ALIAS
|
||||
keyPassword MYAPP_UPLOAD_KEY_PASSWORD
|
||||
}
|
||||
else{
|
||||
storeFile file('debug.keystore')
|
||||
storePassword 'android'
|
||||
keyAlias 'androiddebugkey'
|
||||
keyPassword 'android'
|
||||
}
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
debug {
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
release {
|
||||
// Caution! In production, you need to generate your own keystore file.
|
||||
// see https://reactnative.dev/docs/signed-apk-android.
|
||||
signingConfig signingConfigs.release
|
||||
minifyEnabled enableProguardInReleaseBuilds
|
||||
shrinkResources false
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
}
|
||||
}
|
||||
|
||||
configurations.configureEach {
|
||||
resolutionStrategy {
|
||||
force 'androidx.core:core:1.16.0'
|
||||
force 'androidx.appcompat:appcompat:1.6.1'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("com.facebook.react:react-android")
|
||||
// Agar Hermes band kar ke JSC chahie to:
|
||||
// implementation jscFlavor
|
||||
implementation 'com.google.android.gms:play-services-location:21.0.1'
|
||||
implementation project(':CameraAI')
|
||||
implementation "androidx.activity:activity-ktx:1.8.0"
|
||||
// 🔹 ML Kit dependencies (IMPORTANT)
|
||||
// Barcode scanning
|
||||
implementation "com.google.mlkit:barcode-scanning:17.2.0"
|
||||
// Text recognition (kyunki error me TextRecognizer aa raha hai)
|
||||
implementation "com.google.mlkit:text-recognition:16.0.0"
|
||||
// Import the Firebase BoM
|
||||
implementation(platform("com.google.firebase:firebase-bom:34.10.0"))
|
||||
implementation("com.google.firebase:firebase-analytics")
|
||||
implementation 'com.google.firebase:firebase-messaging'
|
||||
implementation "com.google.firebase:firebase-crashlytics"
|
||||
implementation 'com.facebook.fresco:animated-gif:3.6.0'
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"project_info": {
|
||||
"project_number": "291414129665",
|
||||
"project_id": "performicsone-app",
|
||||
"storage_bucket": "performicsone-app.firebasestorage.app"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:291414129665:android:ffd2b3fa837852cc4dd400",
|
||||
"android_client_info": {
|
||||
"package_name": "com.performics"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyAUUWpFm1yRdtloYHHBiQWryNI6PFvckso"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1",
|
||||
"analytics_enabled": false
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
# --- React Native Camera & ML Kit keep rules ---
|
||||
|
||||
# ML Kit barcode scanning
|
||||
-keep class com.google.mlkit.vision.barcode.** { *; }
|
||||
-dontwarn com.google.mlkit.vision.barcode.**
|
||||
|
||||
# ML Kit vision common
|
||||
-keep class com.google.mlkit.vision.common.** { *; }
|
||||
-dontwarn com.google.mlkit.vision.common.**
|
||||
|
||||
# ML Kit text recognition
|
||||
-keep class com.google.mlkit.vision.text.** { *; }
|
||||
-dontwarn com.google.mlkit.vision.text.**
|
||||
|
||||
# React Native Camera (ya jo bhi tum use kar rahe ho jisme BarcodeDetectorAsyncTask hai)
|
||||
-keep class org.reactnative.camera.** { *; }
|
||||
-dontwarn org.reactnative.camera.**
|
||||
|
||||
# Kabhi-kabhi internal detector classes bhi zaroori hote hain:
|
||||
-keep class com.google.mlkit.vision.** { *; }
|
||||
-dontwarn com.google.mlkit.vision.**
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:targetApi="28"
|
||||
tools:ignore="GoogleAppIndexingWarning"/>
|
||||
</manifest>
|
||||
@@ -0,0 +1,82 @@
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- Permissions -->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
|
||||
<!-- Features -->
|
||||
<!-- <uses-feature android:name="android.hardware.camera" /> -->
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.camera.front" android:required="false" />
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
android:label="@string/app_name"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:allowBackup="false"
|
||||
android:theme="@style/AppTheme"
|
||||
android:hardwareAccelerated="true"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:preserveLegacyExternalStorage="true">
|
||||
|
||||
<!-- Main Activity -->
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
||||
android:launchMode="singleTask"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/AppTheme"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Google Maps API Key -->
|
||||
<meta-data
|
||||
android:name="com.google.android.geo.API_KEY"
|
||||
android:value="AIzaSyCI1EaTZk3eXA_J_UsnBC1STOAFd5unJ4A" />
|
||||
|
||||
<!-- Push Notification Metadata -->
|
||||
<meta-data
|
||||
android:name="com.dieam.reactnativepushnotification.notification_channel_name"
|
||||
android:value="" />
|
||||
<meta-data
|
||||
android:name="com.dieam.reactnativepushnotification.notification_channel_description"
|
||||
android:value="" />
|
||||
|
||||
</application>
|
||||
|
||||
<!-- Queries for Intent (PDF viewer etc.) -->
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<data android:mimeType="application/pdf" />
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
// package com.performics
|
||||
|
||||
// import android.app.Activity
|
||||
// import android.content.Intent
|
||||
// import android.util.Log
|
||||
// import com.cpm.india.cameraai.camera.CameraActivity
|
||||
// import com.facebook.react.bridge.*
|
||||
// import java.io.File
|
||||
// import androidx.activity.result.ActivityResultLauncher
|
||||
// import androidx.activity.result.contract.ActivityResultContracts
|
||||
|
||||
// class CameraaiModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
|
||||
|
||||
// private var cameraPromise: Promise? = null
|
||||
// private var cameraLauncher: ActivityResultLauncher<Intent>? = null
|
||||
|
||||
// init {
|
||||
// setupCameraLauncher()
|
||||
// }
|
||||
|
||||
// private fun setupCameraLauncher() {
|
||||
// val activity = getCurrentActivity()
|
||||
// if (activity is androidx.activity.ComponentActivity && cameraLauncher == null) {
|
||||
// cameraLauncher = activity.registerForActivityResult(
|
||||
// ActivityResultContracts.StartActivityForResult()
|
||||
// ) { result ->
|
||||
// if (result.resultCode == Activity.RESULT_OK && result.data != null) {
|
||||
// val photoPath = result.data!!.getStringExtra("filePath")
|
||||
// cameraPromise?.resolve(photoPath)
|
||||
// } else {
|
||||
// cameraPromise?.reject("CAMERA_CANCELLED", "Camera was cancelled")
|
||||
// }
|
||||
// cameraPromise = null
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// override fun getName(): String = "CameraaiModule"
|
||||
|
||||
// @ReactMethod
|
||||
// fun initializeSDK(options: ReadableMap, promise: Promise) {
|
||||
// try {
|
||||
// val filePath = options.getString("filePath")
|
||||
// ?: throw IllegalArgumentException("filePath is required")
|
||||
|
||||
// val photoFile = File(filePath)
|
||||
// this.cameraPromise = promise
|
||||
|
||||
// val activity = getCurrentActivity()
|
||||
// if (activity == null) {
|
||||
// promise.reject("NO_ACTIVITY", "Activity not available")
|
||||
// return
|
||||
// }
|
||||
|
||||
// if (cameraLauncher == null) setupCameraLauncher()
|
||||
|
||||
// val intent = Intent(activity, CameraActivity::class.java).apply {
|
||||
// putExtra("filePath", photoFile.absolutePath)
|
||||
// putExtra("isGrid", false)
|
||||
// putExtra("isFacingFront", true)
|
||||
// putExtra("isCheckFace", true)
|
||||
// }
|
||||
|
||||
// cameraLauncher?.launch(intent)
|
||||
// ?: promise.reject("LAUNCHER_ERROR", "Launcher not ready")
|
||||
|
||||
// } catch (e: Exception) {
|
||||
// Log.e("CameraaiModule", "Error: ${e.message}", e)
|
||||
// cameraPromise?.reject("ERROR", e.message ?: "Unknown", e)
|
||||
// }
|
||||
// }
|
||||
|
||||
// override fun onCatalystInstanceDestroy() {
|
||||
// cameraLauncher?.unregister()
|
||||
// cameraLauncher = null
|
||||
// super.onCatalystInstanceDestroy()
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
package com.performics
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import com.cpm.india.cameraai.camera.CameraActivity
|
||||
import com.facebook.react.bridge.*
|
||||
|
||||
import java.io.File
|
||||
|
||||
class CameraaiModule(private val reactContext: ReactApplicationContext) :
|
||||
ReactContextBaseJavaModule(reactContext), ActivityEventListener {
|
||||
|
||||
private var cameraPromise: Promise? = null
|
||||
private val CAMERA_REQUEST_CODE = 1001
|
||||
|
||||
init {
|
||||
// Register to receive Activity results
|
||||
reactContext.addActivityEventListener(this)
|
||||
}
|
||||
|
||||
override fun getName(): String = "CameraaiModule"
|
||||
|
||||
@ReactMethod
|
||||
fun initializeSDK(options: ReadableMap, promise: Promise) {
|
||||
try {
|
||||
val filePath = options.getString("filePath")
|
||||
?: throw IllegalArgumentException("filePath is required")
|
||||
|
||||
val photoFile = File(filePath)
|
||||
cameraPromise = promise
|
||||
|
||||
// ✅ Get Activity from reactContext
|
||||
val activity: Activity? = reactContext.currentActivity
|
||||
if (activity == null) {
|
||||
promise.reject("NO_ACTIVITY", "Activity not available")
|
||||
cameraPromise = null
|
||||
return
|
||||
}
|
||||
|
||||
// Create intent to launch CameraActivity
|
||||
val intent = Intent(activity as Context, CameraActivity::class.java).apply {
|
||||
putExtra("filePath", photoFile.absolutePath)
|
||||
putExtra("isGrid", false)
|
||||
putExtra("isFacingFront", true)
|
||||
putExtra("isCheckFace", true)
|
||||
}
|
||||
|
||||
activity.startActivityForResult(intent, CAMERA_REQUEST_CODE)
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e("CameraaiModule", "Error in initializeSDK: ${e.message}", e)
|
||||
cameraPromise?.reject("ERROR", e.message ?: "Unknown error", e)
|
||||
cameraPromise = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(
|
||||
activity: Activity,
|
||||
requestCode: Int,
|
||||
resultCode: Int,
|
||||
data: Intent?
|
||||
) {
|
||||
if (requestCode != CAMERA_REQUEST_CODE || cameraPromise == null) return
|
||||
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
val photoPath = data.getStringExtra("filePath")
|
||||
if (photoPath != null) {
|
||||
cameraPromise?.resolve(photoPath)
|
||||
} else {
|
||||
cameraPromise?.reject("NO_FILEPATH", "No filePath returned from CameraActivity")
|
||||
}
|
||||
} else {
|
||||
cameraPromise?.reject(
|
||||
"CAMERA_CANCELLED",
|
||||
"Camera was cancelled or failed (resultCode = $resultCode)"
|
||||
)
|
||||
}
|
||||
|
||||
cameraPromise = null
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
// Not used, but must be implemented
|
||||
}
|
||||
|
||||
override fun onCatalystInstanceDestroy() {
|
||||
cameraPromise = null
|
||||
super.onCatalystInstanceDestroy()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.performics;
|
||||
|
||||
import com.facebook.react.ReactPackage
|
||||
import com.facebook.react.bridge.ReactApplicationContext
|
||||
import com.facebook.react.uimanager.ViewManager
|
||||
import com.performics.CameraaiModule
|
||||
import com.facebook.react.bridge.NativeModule
|
||||
import java.util.Arrays
|
||||
import java.util.Collections
|
||||
|
||||
class CameraaiPackage : ReactPackage {
|
||||
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
|
||||
return listOf(CameraaiModule(reactContext))
|
||||
}
|
||||
|
||||
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
package com.performics;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ActivityEventListener;
|
||||
import java.lang.String;
|
||||
import java.lang.Boolean;
|
||||
import java.lang.Integer;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.bridge.Promise;
|
||||
|
||||
import android.app.ProgressDialog;
|
||||
import android.widget.Toast;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONException;
|
||||
import android.content.BroadcastReceiver;
|
||||
// import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Paint;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import android.net.Uri;
|
||||
import java.lang.*;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.File;
|
||||
import android.text.TextPaint;
|
||||
import android.text.Layout;
|
||||
import android.text.StaticLayout;
|
||||
|
||||
import java.lang.Thread;
|
||||
import android.graphics.Typeface;
|
||||
|
||||
public class ImageMarkTextModule extends ReactContextBaseJavaModule implements ActivityEventListener{
|
||||
public static final String REACT_CLASS = "ImageMarkText";
|
||||
private static ReactApplicationContext reactContext;
|
||||
private ProgressDialog dialog = null;
|
||||
final Boolean[] isSdkInitialized = new Boolean[1];
|
||||
String returntempSessionId = "";
|
||||
private Promise iRCameraPromise=null;
|
||||
BroadcastReceiver listenForBroadCast;
|
||||
|
||||
|
||||
private int RESULT_OK =-1;
|
||||
|
||||
public ImageMarkTextModule(@NonNull ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
this.reactContext = reactContext;
|
||||
reactContext.addActivityEventListener(this); //Register this native module as Activity result listener
|
||||
Log.d("ImageMarkTextModule", "init module");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewIntent(@NonNull Intent intent) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(@NonNull Activity activity, int requestCode, int resultCode, Intent data) {
|
||||
// Here is your Activity result :)
|
||||
Log.i("ImageMarkTextModule", "onActivityResult: " + resultCode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return REACT_CLASS;
|
||||
}
|
||||
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
@ReactMethod
|
||||
public void NativeImageMarkText(String TextInfo,String ImgInfo,final Promise promise) {
|
||||
// starting the infilect login
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
SimpleDateFormat format = new SimpleDateFormat("MM/DD/yyyy 'at' h:mm:ss a");
|
||||
// Log.d("markText", "Mark Text Start "+format.format(calendar.getTime()));
|
||||
Log.d("markText", "markText Text:"+TextInfo);
|
||||
Log.d("markText", "markText ImgURL:"+ImgInfo);
|
||||
Boolean isSdkLoggedIn=false;
|
||||
|
||||
try{
|
||||
JSONObject TextObj = new JSONObject(TextInfo);
|
||||
JSONObject ImgObj = new JSONObject(ImgInfo);
|
||||
class MarkTextApp {
|
||||
public String getImageUri(Bitmap inImage) {
|
||||
try{
|
||||
Calendar calendar1 = Calendar.getInstance();
|
||||
SimpleDateFormat format1 = new SimpleDateFormat("MM/DD/yyyy 'at' h:mm:ss a");
|
||||
File tempFile = File.createTempFile("testtempimg", ".jpg");
|
||||
ByteArrayOutputStream bytes =new ByteArrayOutputStream();
|
||||
inImage.compress(Bitmap.CompressFormat.JPEG, 90, bytes);
|
||||
byte bitmapData[] = bytes.toByteArray();
|
||||
FileOutputStream fileOutPut = new FileOutputStream(tempFile);
|
||||
fileOutPut.write(bitmapData);
|
||||
fileOutPut.flush();
|
||||
fileOutPut.close();
|
||||
|
||||
Uri uri=Uri.fromFile(tempFile);
|
||||
return uri.toString();
|
||||
}catch(Exception e) {
|
||||
Log.d("markText", "Error while generating local file : "+e.getMessage());
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
public void CanvasMarkText() {
|
||||
|
||||
Thread thread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Calendar calendar1 = Calendar.getInstance();
|
||||
SimpleDateFormat format1 = new SimpleDateFormat("MM/DD/yyyy 'at' h:mm:ss a");
|
||||
|
||||
|
||||
int mColorBackground=Color.parseColor("#ffffffff");
|
||||
int mTextColor=Color.parseColor("red");
|
||||
|
||||
String Text=TextObj.getString("text");
|
||||
String BottomText=TextObj.getString("BottomText");
|
||||
JSONObject TextStyle=TextObj.getJSONObject("textStyle");
|
||||
String TopTextfontSize=TextStyle.getString("TopTextfontSize");
|
||||
String TopText_x=TextStyle.getString("TopText_x");
|
||||
String TopText_y=TextStyle.getString("TopText_y");
|
||||
Float TopTextfontSize_F = Float.parseFloat(TopTextfontSize);
|
||||
Float TopText_xF = Float.parseFloat(TopText_x);
|
||||
Float TopText_yF = Float.parseFloat(TopText_y);
|
||||
|
||||
String BottomTextfontSize=TextStyle.getString("BottomTextfontSize");
|
||||
String BottomText_x=TextStyle.getString("BottomText_x");
|
||||
String BottomText_y=TextStyle.getString("BottomText_y");
|
||||
int BottomTextfontSize_F = Integer.parseInt(BottomTextfontSize);
|
||||
int BottomText_xF = Integer.parseInt(BottomText_x);
|
||||
int BottomText_yF = Integer.parseInt(BottomText_y);
|
||||
|
||||
String src=ImgObj.getString("src");
|
||||
String height=ImgObj.getString("height");
|
||||
String ExtendedHeight=ImgObj.getString("ExtendedHeight");
|
||||
String width=ImgObj.getString("width");
|
||||
|
||||
|
||||
BitmapFactory.Options opt = new BitmapFactory.Options();
|
||||
opt.inMutable = true;
|
||||
Bitmap bMap = BitmapFactory.decodeFile(src,opt);
|
||||
|
||||
Bitmap bg_bMap=Bitmap.createBitmap(Integer.parseInt(width), Integer.parseInt(ExtendedHeight), Bitmap.Config.ARGB_8888);
|
||||
// bMap= bMap.copy(Bitmap.Config.ARGB_8888, true);
|
||||
Canvas mCanvas = new Canvas(bg_bMap);
|
||||
mCanvas.drawColor(mColorBackground);
|
||||
|
||||
|
||||
Paint paint = new Paint();
|
||||
mCanvas.drawBitmap(bMap,0f,0f,paint);
|
||||
|
||||
paint.setColor(mTextColor);
|
||||
//Typeface tf =Typeface.createFromAsset(reactContext.getAssets(),"fonts/Roboto-Regular.ttf");
|
||||
paint.setTypeface(Typeface.DEFAULT);
|
||||
paint.setTextSize(TopTextfontSize_F);
|
||||
mCanvas.drawText(Text, TopText_xF, TopText_yF, paint);
|
||||
|
||||
// paint.setTextSize(BottomTextfontSize_F);
|
||||
// mCanvas.drawText(BottomText, BottomText_xF, BottomText_yF, paint);
|
||||
|
||||
// Drawable d = new BitmapDrawable(bMap);
|
||||
// d.setBounds(10, 10, 0, 0);
|
||||
// d.draw(canvas);
|
||||
|
||||
// String BottomText = "This is some text. This is some text. This is some text. This is some text. This is some text. This is some text.";
|
||||
|
||||
TextPaint myTextPaint = new TextPaint();
|
||||
myTextPaint.setTextSize(BottomTextfontSize_F);
|
||||
myTextPaint.setColor(mTextColor);
|
||||
myTextPaint.setTypeface(Typeface.DEFAULT);
|
||||
|
||||
|
||||
int txt_width = Integer.parseInt(width);
|
||||
Layout.Alignment alignment = Layout.Alignment.ALIGN_NORMAL;
|
||||
float spacingMultiplier = 1;
|
||||
float spacingAddition = 0;
|
||||
boolean includePadding = false;
|
||||
|
||||
StaticLayout myStaticLayout = new StaticLayout(BottomText, myTextPaint, txt_width, alignment, spacingMultiplier, spacingAddition, includePadding);
|
||||
mCanvas.save();
|
||||
float txt_gheight = myStaticLayout.getHeight();
|
||||
mCanvas.translate(BottomText_xF, BottomText_yF);
|
||||
|
||||
//draws static layout on canvas
|
||||
myStaticLayout.draw(mCanvas);
|
||||
mCanvas.restore();
|
||||
|
||||
|
||||
|
||||
String url=getImageUri(bg_bMap);
|
||||
promise.resolve(url);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
promise.resolve(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
thread.start();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
MarkTextApp mImgObj= new MarkTextApp();
|
||||
mImgObj.CanvasMarkText();
|
||||
|
||||
}
|
||||
catch(JSONException je) {
|
||||
Log.d("markText", "markText JSON Parse Error");
|
||||
Toast.makeText(reactContext,"markText failed (JSON Parse Error): "+je.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
je.printStackTrace();
|
||||
promise.resolve(null);
|
||||
}
|
||||
catch(Exception e){
|
||||
Log.d("markText", "Error : "+e.getMessage());
|
||||
e.printStackTrace();
|
||||
promise.resolve(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.performics;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import com.facebook.react.HeadlessJsTaskService;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.jstasks.HeadlessJsTaskConfig;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
// import com.facebook.react.bridge.ReadableArray;
|
||||
// import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import java.lang.Runnable;
|
||||
import java.lang.String;
|
||||
import com.performics.ImageMarkTextModule;
|
||||
import com.facebook.react.ReactNativeHost;
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
|
||||
public class ImageMarkTextPackage implements ReactPackage {
|
||||
@Override
|
||||
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
||||
List<NativeModule> modules = new ArrayList<>();
|
||||
modules.add(new ImageMarkTextModule(reactContext));
|
||||
return modules;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.performics
|
||||
import android.os.Bundle
|
||||
import com.facebook.react.ReactActivity
|
||||
import com.facebook.react.ReactActivityDelegate
|
||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
|
||||
import com.facebook.react.defaults.DefaultReactActivityDelegate
|
||||
import org.devio.rn.splashscreen.SplashScreen
|
||||
|
||||
|
||||
|
||||
class MainActivity : ReactActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
SplashScreen.show(this)
|
||||
super.onCreate(null)
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
// Prevent crash from react-native-screens
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the main component registered from JavaScript. This is used to schedule
|
||||
* rendering of the component.
|
||||
*/
|
||||
override fun getMainComponentName(): String = "Performics"
|
||||
|
||||
/**
|
||||
* Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
|
||||
* which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
|
||||
*/
|
||||
override fun createReactActivityDelegate(): ReactActivityDelegate =
|
||||
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.performics
|
||||
|
||||
import android.app.Application
|
||||
import com.facebook.react.PackageList
|
||||
import com.facebook.react.ReactApplication
|
||||
import com.facebook.react.ReactHost
|
||||
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
|
||||
import com.facebook.react.ReactNativeHost
|
||||
import com.facebook.react.ReactPackage
|
||||
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
|
||||
import com.facebook.react.defaults.DefaultReactNativeHost
|
||||
import com.performics.OpenDevOptionsPackage
|
||||
//import com.performics.ObjectDetectionPackage
|
||||
|
||||
class MainApplication : Application(), ReactApplication {
|
||||
|
||||
override val reactNativeHost: ReactNativeHost =
|
||||
object : DefaultReactNativeHost(this) {
|
||||
override fun getPackages(): List<ReactPackage> =
|
||||
PackageList(this).packages.apply {
|
||||
// Add your custom packages here
|
||||
addAll(listOf(
|
||||
ImageMarkTextPackage(),
|
||||
CameraaiPackage(),
|
||||
OpenDevOptionsPackage(),
|
||||
// ObjectDetectionPackage(),
|
||||
))
|
||||
}
|
||||
override fun getJSMainModuleName(): String = "index"
|
||||
|
||||
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
|
||||
|
||||
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
|
||||
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
|
||||
}
|
||||
|
||||
override val reactHost: ReactHost
|
||||
get() = getDefaultReactHost(applicationContext, reactNativeHost)
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
loadReactNative(this)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.performics;
|
||||
import android.content.Intent;
|
||||
import android.provider.Settings;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import android.app.Activity;
|
||||
import android.util.Log;
|
||||
|
||||
|
||||
|
||||
|
||||
public class OpenDevOptionsModule extends ReactContextBaseJavaModule {
|
||||
private static ReactApplicationContext reactContext;
|
||||
|
||||
public OpenDevOptionsModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
this.reactContext = reactContext;
|
||||
Log.d("OpenDevOptionsModule", "init module");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "OpenDevOptions";
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void open() {
|
||||
Log.d("OpenDevOptionsModule", "open");
|
||||
Intent intent = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
reactContext.startActivity(intent);
|
||||
Log.d("OpenDevOptionsModule", "open1");
|
||||
}
|
||||
|
||||
// Check if Developer Options Enabled
|
||||
@ReactMethod
|
||||
public void isDevOptionsEnabled(Promise promise) {
|
||||
try {
|
||||
Log.d("OpenDevOptionsModule", "isDevOptionsEnabled");
|
||||
int devOptions = Settings.Global.getInt(
|
||||
reactContext.getContentResolver(),
|
||||
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED,
|
||||
0
|
||||
);
|
||||
promise.resolve(devOptions == 1);
|
||||
} catch (Exception e) {
|
||||
Log.d("OpenDevOptionsModule", e.toString());
|
||||
promise.reject("ERROR", e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.performics;
|
||||
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
import com.performics.OpenDevOptionsModule;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class OpenDevOptionsPackage implements ReactPackage {
|
||||
|
||||
@Override
|
||||
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
||||
List<NativeModule> modules = new ArrayList<>();
|
||||
modules.add(new OpenDevOptionsModule(reactContext));
|
||||
return modules;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:fromXDelta="-100%"
|
||||
android:toXDelta="0"
|
||||
android:duration="200" />
|
||||
</set>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:fromXDelta="0"
|
||||
android:toXDelta="100%"
|
||||
android:duration="200" />
|
||||
</set>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:fromXDelta="100%"
|
||||
android:toXDelta="0"
|
||||
android:duration="300" />
|
||||
</set>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:fromXDelta="0"
|
||||
android:toXDelta="-100%"
|
||||
android:duration="300" />
|
||||
</set>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<alpha
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fromAlpha="0.0"
|
||||
android:toAlpha="1.0"
|
||||
android:duration="3000" />
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@android:anim/bounce_interpolator">
|
||||
<translate
|
||||
android:fromYDelta="-100%p"
|
||||
android:toYDelta="0"
|
||||
android:duration="2000"/>
|
||||
</set>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:ordering="sequentially"
|
||||
android:shareInterpolator="false">
|
||||
|
||||
<scale
|
||||
android:interpolator="@android:anim/linear_interpolator"
|
||||
android:fromXScale="1.0"
|
||||
android:toXScale="1.1"
|
||||
android:fromYScale="1.0"
|
||||
android:toYScale="1.0"
|
||||
android:duration="500"
|
||||
android:pivotX="70%"
|
||||
android:pivotY="70%" />
|
||||
|
||||
<scale
|
||||
android:interpolator="@android:anim/bounce_interpolator"
|
||||
android:fromXScale="1.1"
|
||||
android:fromYScale="1.1"
|
||||
android:toXScale="1.0"
|
||||
android:toYScale="1.0"
|
||||
android:pivotX="70%"
|
||||
android:pivotY="70%"
|
||||
android:duration="1000"
|
||||
android:startOffset="500" />
|
||||
|
||||
</set>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fillAfter="true">
|
||||
|
||||
<!--Move-->
|
||||
<translate
|
||||
android:duration="1000"
|
||||
android:fromXDelta="-150%"
|
||||
android:fromYDelta="-150%"
|
||||
android:interpolator="@android:anim/linear_interpolator"
|
||||
android:toXDelta="0%"
|
||||
android:toYDelta="0%"></translate>
|
||||
|
||||
<!--Fade Out-->
|
||||
<alpha
|
||||
android:duration="2000"
|
||||
android:fromAlpha="1.0"
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:toAlpha="0.0"></alpha>
|
||||
|
||||
</set>
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fillAfter="true">
|
||||
|
||||
<!-- Rotate -->
|
||||
<rotate
|
||||
android:duration="500"
|
||||
android:fromDegrees="30"
|
||||
android:interpolator="@android:anim/linear_interpolator"
|
||||
android:pivotX="50%"
|
||||
android:pivotY="50%"
|
||||
android:repeatCount="4"
|
||||
android:repeatMode="reverse"
|
||||
android:toDegrees="0"></rotate>
|
||||
|
||||
<!--Move-->
|
||||
<translate
|
||||
android:duration="1000"
|
||||
android:fromXDelta="150%"
|
||||
android:fromYDelta="150%"
|
||||
android:interpolator="@android:anim/linear_interpolator"
|
||||
android:toXDelta="0%"
|
||||
android:toYDelta="0%"></translate>
|
||||
|
||||
<!--Fade In-->
|
||||
<alpha
|
||||
android:duration="2000"
|
||||
android:fromAlpha="0.0"
|
||||
android:interpolator="@android:anim/decelerate_interpolator"
|
||||
android:toAlpha="1.0"></alpha>
|
||||
|
||||
</set>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fillAfter="true">
|
||||
|
||||
<!--Move-->
|
||||
<translate
|
||||
android:duration="1000"
|
||||
android:fromXDelta="-170%"
|
||||
android:fromYDelta="-25%"
|
||||
android:interpolator="@android:anim/linear_interpolator"
|
||||
android:toXDelta="0%"
|
||||
android:toYDelta="0%"></translate>
|
||||
|
||||
<!--Fade Out-->
|
||||
<alpha
|
||||
android:duration="2000"
|
||||
android:fromAlpha="1.0"
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:toAlpha="0.0"></alpha>
|
||||
|
||||
</set>
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fillAfter="true">
|
||||
|
||||
<!-- Rotate -->
|
||||
<rotate
|
||||
android:duration="500"
|
||||
android:fromDegrees="30"
|
||||
android:interpolator="@android:anim/linear_interpolator"
|
||||
android:pivotX="50%"
|
||||
android:pivotY="50%"
|
||||
android:repeatCount="4"
|
||||
android:repeatMode="reverse"
|
||||
android:toDegrees="0"></rotate>
|
||||
|
||||
<!--Move-->
|
||||
<translate
|
||||
android:duration="1000"
|
||||
android:fromXDelta="170%"
|
||||
android:fromYDelta="25%"
|
||||
android:interpolator="@android:anim/linear_interpolator"
|
||||
android:toXDelta="0%"
|
||||
android:toYDelta="0%"></translate>
|
||||
|
||||
<!--Fade In-->
|
||||
<alpha
|
||||
android:duration="2000"
|
||||
android:fromAlpha="0.0"
|
||||
android:interpolator="@android:anim/decelerate_interpolator"
|
||||
android:toAlpha="1.0"></alpha>
|
||||
|
||||
</set>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2011 - Riccardo Ciovati
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate android:fromYDelta="-50%p" android:toYDelta="0" android:duration="200"/>
|
||||
<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="200" />
|
||||
</set>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<translate
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fromXDelta="0%"
|
||||
android:toXDelta="0%"
|
||||
android:fromYDelta="200%"
|
||||
android:toYDelta="0%"
|
||||
android:duration="2000"
|
||||
android:zAdjustment="top" />
|
||||
|
||||
</set>
|
||||
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 38 KiB |
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2014 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<inset xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:insetLeft="@dimen/abc_edit_text_inset_horizontal_material"
|
||||
android:insetRight="@dimen/abc_edit_text_inset_horizontal_material"
|
||||
android:insetTop="@dimen/abc_edit_text_inset_top_material"
|
||||
android:insetBottom="@dimen/abc_edit_text_inset_bottom_material">
|
||||
|
||||
<selector>
|
||||
<!--
|
||||
This file is a copy of abc_edit_text_material (https://bit.ly/3k8fX7I).
|
||||
The item below with state_pressed="false" and state_focused="false" causes a NullPointerException.
|
||||
NullPointerException:tempt to invoke virtual method 'android.graphics.drawable.Drawable android.graphics.drawable.Drawable$ConstantState.newDrawable(android.content.res.Resources)'
|
||||
|
||||
<item android:state_pressed="false" android:state_focused="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
|
||||
|
||||
For more info, see https://bit.ly/3CdLStv (react-native/pull/29452) and https://bit.ly/3nxOMoR.
|
||||
-->
|
||||
<item android:state_enabled="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
|
||||
<item android:drawable="@drawable/abc_textfield_activated_mtrl_alpha"/>
|
||||
</selector>
|
||||
|
||||
</inset>
|
||||
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/white"
|
||||
android:id="@+id/lin_lay"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:weightSum="10">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="2">
|
||||
|
||||
|
||||
<ImageView
|
||||
android:layout_width="226dp"
|
||||
android:layout_height="53dp"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="@dimen/custom_layout_margin"
|
||||
android:src="@drawable/parinaam_tag_line"
|
||||
android:visibility="visible" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="8"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:gravity="center"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/logo"
|
||||
android:layout_width="157dp"
|
||||
android:layout_height="161dp"
|
||||
android:gravity="center"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:background="@drawable/logo"
|
||||
android:visibility="visible"
|
||||
android:layout_marginTop="-100dp"
|
||||
/>
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="primary_dark">#000000</color>
|
||||
<color name="primary_color">#6B84F6</color>
|
||||
|
||||
<color name="colorPrimary">#294D8C</color>
|
||||
<color name="colorPrimaryDark">#383386</color>
|
||||
<color name="colorAccent">#87CEFA</color>
|
||||
<color name="primarycolor">#294D8C</color>
|
||||
<color name="white">#FFFFFF</color>
|
||||
<color name="lightpink">#fe8bd0</color>
|
||||
<color name="black">#000000</color>
|
||||
<color name="light_yellow">#FFF176</color>
|
||||
<color name="text_yellow">#f9f93d</color>
|
||||
<color name="red">#e21c22</color>
|
||||
<color name="transparent">#00000000</color>
|
||||
<color name="green">#4CAF50</color>
|
||||
<color name="teal_dark">#294D8C</color>
|
||||
<color name="teal_light">#009688</color>
|
||||
<color name="green_dark">#388E3C</color>
|
||||
<color name="teal_header">#00796B</color>
|
||||
<color name="green_light">#66BB6A</color>
|
||||
<color name="grey_background">#D3D3D3</color>
|
||||
<color name="grey_light">#FAFAFA</color>
|
||||
<color name="colorPSecond">#00bfff</color>
|
||||
<color name="darkblue">#1E88E5</color>
|
||||
<color name="lightsalmon">#FFA07A</color>
|
||||
<color name="lightskyblue">#87CEFA</color>
|
||||
<color name="gainsboro">#DCDCDC</color>
|
||||
<color name="peachpuff">#FFDAB9</color>
|
||||
<color name="ColorPrimaryLight">#1a7be0</color>
|
||||
<color name="text_grey_color">#c8c3c3</color>
|
||||
<color name="grey_dark_background">#888</color>
|
||||
<color name="circular_progress_default_progress">#bada55</color>
|
||||
<color name="circular_progress_default_background">#787878</color>
|
||||
<color name="circular_progress_default_title">#bada55</color>
|
||||
<color name="circular_progress_default_subtitle">#D1D1D1</color>
|
||||
<color name="darkgrey">#A9A9A9</color>
|
||||
<color name="transparent_white">#F7F7F7</color>
|
||||
<color name="background_color">#E1E2E2</color>
|
||||
<color name="very_dark_blue">@android:color/transparent</color>
|
||||
<!-- <color name="very_dark_blue">#2A2B33</color>-->
|
||||
<color name="light_blue">#E6F8FF</color>
|
||||
<color name="gray_for_text_color">#5a5a5a</color>
|
||||
<color name="per_closed">@color/colorPrimary</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,34 @@
|
||||
<resources>
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
<dimen name="custom_margin">5dp</dimen>
|
||||
<dimen name="nav_header_height">160dp</dimen>
|
||||
<dimen name="fab_margin">16dp</dimen>
|
||||
<dimen name="text_size_normal">15sp</dimen>
|
||||
<dimen name="text_size_small">16sp</dimen>
|
||||
<dimen name="text_size_medium">18sp</dimen>
|
||||
<dimen name="store_entry_text_size">15sp</dimen>
|
||||
<dimen name="text_size_very_small">12sp</dimen>
|
||||
<dimen name="text_size_14sp">14sp</dimen>
|
||||
<dimen name="text_size_13sp">13sp</dimen>
|
||||
<dimen name="appbar_padding_top">8dp</dimen>
|
||||
<dimen name="padding_standard">5dp</dimen>
|
||||
<dimen name="margin11dp">11dp</dimen>
|
||||
<dimen name="margin1dp">1dp</dimen>
|
||||
|
||||
<dimen name="custom_layout_margin">30dp</dimen>
|
||||
<dimen name="text_size_big">25sp</dimen>
|
||||
|
||||
<dimen name="button_margin">15dp</dimen>
|
||||
<dimen name="txt_size">16sp</dimen>
|
||||
<dimen name="txt_size2dp">2dp</dimen>
|
||||
<dimen name="txt_3dp">3dp</dimen>
|
||||
<dimen name="margin10dp">10dp</dimen>
|
||||
<dimen name="store_p_activity_vertical_margin">8dp</dimen>
|
||||
|
||||
<dimen name="custom_layout_margin35">35dp</dimen>
|
||||
<dimen name="hight40dp">40dp</dimen>
|
||||
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Performics</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<!-- React Native edit text -->
|
||||
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
|
||||
<!-- Prevent dark mode usage -->
|
||||
<item name="android:forceDarkAllowed" tools:targetApi="29">false</item>
|
||||
<!-- Primary colors -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorAccent">@color/colorPrimary</item>
|
||||
<!-- IMPORTANT: status bar color -->
|
||||
<item name="android:statusBarColor">@color/colorPrimary</item>
|
||||
<!-- Make sure status bar is NOT translucent -->
|
||||
<item name="android:windowTranslucentStatus">false</item>
|
||||
<!-- Custom. -->
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowSoftInputMode">adjustResize</item>
|
||||
<item name="android:hardwareAccelerated">true</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,64 @@
|
||||
buildscript {
|
||||
ext {
|
||||
buildToolsVersion = "36.0.0"
|
||||
minSdkVersion = 24
|
||||
compileSdkVersion = 36
|
||||
targetSdkVersion = 34
|
||||
ndkVersion = "27.1.12297006"
|
||||
kotlinVersion = "2.1.20"
|
||||
googlePlayServicesVersion = "21.0.1"
|
||||
googlePlayServicesMapsVersion = "18.2.0"
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath('com.android.tools.build:gradle:8.13.2')
|
||||
classpath("com.facebook.react:react-native-gradle-plugin")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
|
||||
|
||||
classpath("com.google.gms:google-services:4.4.2")
|
||||
classpath("com.google.firebase:firebase-crashlytics-gradle:2.9.9")
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
maven { url("$rootDir/../node_modules/react-native/android") }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Block 1 – tumhara existing Google Play Services resolution
|
||||
*/
|
||||
subprojects {
|
||||
configurations.all {
|
||||
resolutionStrategy.eachDependency { details ->
|
||||
if (details.requested.group == 'com.google.android.gms') {
|
||||
if (details.requested.name == 'play-services-location') {
|
||||
details.useVersion "21.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Block 2 – saare Kotlin Android modules ke liye JVM target 17
|
||||
*/
|
||||
subprojects { subproject ->
|
||||
subproject.plugins.withId("org.jetbrains.kotlin.android") {
|
||||
subproject.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: "com.facebook.react.rootproject"
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# Project-wide Gradle settings.
|
||||
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
|
||||
# org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
|
||||
|
||||
|
||||
# Gradle Daemon
|
||||
org.gradle.daemon=true
|
||||
|
||||
# Increase Gradle memory
|
||||
org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8
|
||||
|
||||
# Enable parallel builds
|
||||
org.gradle.parallel=true
|
||||
|
||||
# Optional: Enable configuration on demand
|
||||
org.gradle.configureondemand=true
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
# Use this property to specify which architecture you want to build.
|
||||
# You can also override it from the CLI using
|
||||
# ./gradlew <task> -PreactNativeArchitectures=x86_64
|
||||
# reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
|
||||
reactNativeArchitectures=armeabi-v7a,arm64-v8a
|
||||
|
||||
|
||||
# Use this property to enable support to the new architecture.
|
||||
# This will allow you to use TurboModules and the Fabric render in
|
||||
# your application. You should enable this flag either if you want
|
||||
# to write custom TurboModules/Fabric components OR use libraries that
|
||||
# are providing them.
|
||||
newArchEnabled=true
|
||||
cmake.maxPathLength=0
|
||||
|
||||
|
||||
# Use this property to enable or disable the Hermes JS engine.
|
||||
# If set to false, you will be using JSC instead.
|
||||
hermesEnabled=true
|
||||
|
||||
# Use this property to enable edge-to-edge display support.
|
||||
# This allows your app to draw behind system bars for an immersive UI.
|
||||
# Note: Only works with ReactActivity and should not be used with custom Activity.
|
||||
edgeToEdgeEnabled=false
|
||||
set=MAX_WATCHER=8192
|
||||
@@ -0,0 +1,8 @@
|
||||
#Tue Jan 06 10:16:50 IST 2026
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -0,0 +1,251 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH="\\\"\\\""
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
@@ -0,0 +1,99 @@
|
||||
@REM Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
@REM
|
||||
@REM This source code is licensed under the MIT license found in the
|
||||
@REM LICENSE file in the root directory of this source tree.
|
||||
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -0,0 +1,8 @@
|
||||
pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") }
|
||||
plugins { id("com.facebook.react.settings") }
|
||||
extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
|
||||
rootProject.name = 'Performics'
|
||||
include ':app'
|
||||
includeBuild('../node_modules/@react-native/gradle-plugin')
|
||||
include ':CameraAI'
|
||||
|
||||