commit bd9ef394867e549f25be61d4b3ca5dd626a42265
parent 8d2353bbbec41fe5ce286821a0fee55791eb933e
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date:   Thu, 22 Aug 2024 09:52:18 +0200

fix(core): camera tweaks load

Diffstat:
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/tweaks/CameraTweaks.kt | 123+++++++++++++++++++++++++++++++++++++++----------------------------------------
1 file changed, 61 insertions(+), 62 deletions(-)

diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/tweaks/CameraTweaks.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/tweaks/CameraTweaks.kt @@ -19,94 +19,93 @@ import java.io.ByteArrayOutputStream import java.nio.ByteBuffer class CameraTweaks : Feature("Camera Tweaks") { - private fun parseResolution(resolution: String): IntArray? { return runCatching { resolution.split("x").map { it.toInt() }.toIntArray() }.getOrNull() } @SuppressLint("MissingPermission", "DiscouragedApi") override fun init() { - onNextActivityCreate { - val config = context.config.camera + val config = context.config.camera - val frontCameraId = runCatching { context.androidContext.getSystemService(CameraManager::class.java).run { + val frontCameraId by lazy { + runCatching { context.androidContext.getSystemService(CameraManager::class.java).run { cameraIdList.firstOrNull { getCameraCharacteristics(it).get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT } } }.getOrNull() + } - if (config.disableCameras.get().isNotEmpty() && frontCameraId != null) { - ContextWrapper::class.java.hook("checkPermission", HookStage.BEFORE) { param -> - val permission = param.arg<String>(0) - if (permission == Manifest.permission.CAMERA) { - param.setResult(PackageManager.PERMISSION_GRANTED) - } + if (config.disableCameras.get().isNotEmpty() && frontCameraId != null) { + ContextWrapper::class.java.hook("checkPermission", HookStage.BEFORE) { param -> + val permission = param.arg<String>(0) + if (permission == Manifest.permission.CAMERA) { + param.setResult(PackageManager.PERMISSION_GRANTED) } } + } - var isLastCameraFront = false + var isLastCameraFront = false - CameraManager::class.java.hook("openCamera", HookStage.BEFORE) { param -> - val cameraManager = param.thisObject() as? CameraManager ?: return@hook - val cameraId = param.arg<String>(0) - val disabledCameras = config.disableCameras.get() + CameraManager::class.java.hook("openCamera", HookStage.BEFORE) { param -> + val cameraManager = param.thisObject() as? CameraManager ?: return@hook + val cameraId = param.arg<String>(0) + val disabledCameras = config.disableCameras.get() - if (disabledCameras.size >= 2) { - param.setResult(null) - return@hook - } + if (disabledCameras.size >= 2) { + param.setResult(null) + return@hook + } - isLastCameraFront = cameraId == frontCameraId + isLastCameraFront = cameraId == frontCameraId - if (disabledCameras.size != 1) return@hook + if (disabledCameras.size != 1) return@hook - // trick to replace unwanted camera with another one - if ((disabledCameras.contains("front") && isLastCameraFront) || (disabledCameras.contains("back") && !isLastCameraFront)) { - param.setArg(0, cameraManager.cameraIdList.filterNot { it == cameraId }.firstOrNull() ?: return@hook) - isLastCameraFront = !isLastCameraFront - } + // trick to replace unwanted camera with another one + if ((disabledCameras.contains("front") && isLastCameraFront) || (disabledCameras.contains("back") && !isLastCameraFront)) { + param.setArg(0, cameraManager.cameraIdList.filterNot { it == cameraId }.firstOrNull() ?: return@hook) + isLastCameraFront = !isLastCameraFront } + } - ImageReader::class.java.hook("newInstance", HookStage.BEFORE) { param -> - val captureResolutionConfig = config.customResolution.getNullable()?.takeIf { it.isNotEmpty() }?.let { parseResolution(it) } - ?: (if (isLastCameraFront) config.overrideFrontResolution.getNullable() else config.overrideBackResolution.getNullable())?.let { parseResolution(it) } ?: return@hook - param.setArg(0, captureResolutionConfig[0]) - param.setArg(1, captureResolutionConfig[1]) - } + ImageReader::class.java.hook("newInstance", HookStage.BEFORE) { param -> + val captureResolutionConfig = config.customResolution.getNullable()?.takeIf { it.isNotEmpty() }?.let { parseResolution(it) } + ?: (if (isLastCameraFront) config.overrideFrontResolution.getNullable() else config.overrideBackResolution.getNullable())?.let { parseResolution(it) } ?: return@hook + param.setArg(0, captureResolutionConfig[0]) + param.setArg(1, captureResolutionConfig[1]) + } + + CameraCharacteristics::class.java.hook("get", HookStage.AFTER) { param -> + val key = param.argNullable<Key<*>>(0) ?: return@hook - CameraCharacteristics::class.java.hook("get", HookStage.AFTER) { param -> - val key = param.argNullable<Key<*>>(0) ?: return@hook - - if (key == CameraCharacteristics.LENS_FACING) { - val disabledCameras = config.disableCameras.get() - //FIXME: unexpected behavior when app is resumed - if (disabledCameras.size == 1) { - val isFrontCamera = param.getResult() as? Int == CameraCharacteristics.LENS_FACING_FRONT - if ((disabledCameras.contains("front") && isFrontCamera) || (disabledCameras.contains("back") && !isFrontCamera)) { - param.setResult(if (isFrontCamera) CameraCharacteristics.LENS_FACING_BACK else CameraCharacteristics.LENS_FACING_FRONT) - } + if (key == CameraCharacteristics.LENS_FACING) { + val disabledCameras = config.disableCameras.get() + //FIXME: unexpected behavior when app is resumed + if (disabledCameras.size == 1) { + val isFrontCamera = param.getResult() as? Int == CameraCharacteristics.LENS_FACING_FRONT + if ((disabledCameras.contains("front") && isFrontCamera) || (disabledCameras.contains("back") && !isFrontCamera)) { + param.setResult(if (isFrontCamera) CameraCharacteristics.LENS_FACING_BACK else CameraCharacteristics.LENS_FACING_FRONT) } } + } - if (key == CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES) { - val isFrontCamera = param.invokeOriginal( - arrayOf(CameraCharacteristics.LENS_FACING) - ) == CameraCharacteristics.LENS_FACING_FRONT - val customFrameRate = (if (isFrontCamera) config.frontCustomFrameRate.getNullable() else config.backCustomFrameRate.getNullable())?.toIntOrNull() ?: return@hook - param.setResult(arrayOf(Range(customFrameRate, customFrameRate))) - } + if (key == CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES) { + val isFrontCamera = param.invokeOriginal( + arrayOf(CameraCharacteristics.LENS_FACING) + ) == CameraCharacteristics.LENS_FACING_FRONT + val customFrameRate = (if (isFrontCamera) config.frontCustomFrameRate.getNullable() else config.backCustomFrameRate.getNullable())?.toIntOrNull() ?: return@hook + param.setResult(arrayOf(Range(customFrameRate, customFrameRate))) } + } - if (config.blackPhotos.get()) { - findClass("android.media.ImageReader\$SurfaceImage").hook("getPlanes", HookStage.AFTER) { param -> - val image = param.thisObject() as? Image ?: return@hook - val planes = param.getResult() as? Array<*> ?: return@hook - val output = ByteArrayOutputStream() - Bitmap.createBitmap(image.width, image.height, Bitmap.Config.ARGB_8888).apply { - compress(Bitmap.CompressFormat.JPEG, 100, output) - recycle() - } - planes.filterNotNull().forEach { plane -> - plane.setObjectField("mBuffer", ByteBuffer.wrap(output.toByteArray())) - } + if (config.blackPhotos.get()) { + findClass("android.media.ImageReader\$SurfaceImage").hook("getPlanes", HookStage.AFTER) { param -> + val image = param.thisObject() as? Image ?: return@hook + val planes = param.getResult() as? Array<*> ?: return@hook + val output = ByteArrayOutputStream() + Bitmap.createBitmap(image.width, image.height, Bitmap.Config.ARGB_8888).apply { + compress(Bitmap.CompressFormat.JPEG, 100, output) + recycle() + } + planes.filterNotNull().forEach { plane -> + plane.setObjectField("mBuffer", ByteBuffer.wrap(output.toByteArray())) } } }