Merge pull request #210 from esensar/fix/camera-null-crashes

Prevent null cameraId in CameraFlash
This commit is contained in:
Tibor Kaputa 2023-09-20 12:11:55 +02:00 committed by GitHub
commit ceed63aaa4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 25 deletions

View File

@ -15,7 +15,7 @@ internal class CameraFlash(
private var cameraTorchListener: CameraTorchListener? = null, private var cameraTorchListener: CameraTorchListener? = null,
) { ) {
private val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager private val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
private var cameraId: String? = null private val cameraId: String
private val torchCallback = object : CameraManager.TorchCallback() { private val torchCallback = object : CameraManager.TorchCallback() {
override fun onTorchModeChanged(cameraId: String, enabled: Boolean) { override fun onTorchModeChanged(cameraId: String, enabled: Boolean) {
@ -28,10 +28,11 @@ internal class CameraFlash(
} }
init { init {
try { cameraId = try {
cameraId = manager.cameraIdList[0] ?: "0" manager.cameraIdList[0] ?: "0"
} catch (e: Exception) { } catch (e: Exception) {
context.showErrorToast(e) context.showErrorToast(e)
"0"
} }
} }
@ -41,7 +42,7 @@ internal class CameraFlash(
val brightnessLevel = getCurrentBrightnessLevel() val brightnessLevel = getCurrentBrightnessLevel()
changeTorchBrightness(brightnessLevel) changeTorchBrightness(brightnessLevel)
} else { } else {
manager.setTorchMode(cameraId!!, enable) manager.setTorchMode(cameraId, enable)
} }
} catch (e: Exception) { } catch (e: Exception) {
context.showErrorToast(e) context.showErrorToast(e)
@ -54,13 +55,13 @@ internal class CameraFlash(
fun changeTorchBrightness(level: Int) { fun changeTorchBrightness(level: Int) {
if (isTiramisuPlus()) { if (isTiramisuPlus()) {
manager.turnOnTorchWithStrengthLevel(cameraId!!, level) manager.turnOnTorchWithStrengthLevel(cameraId, level)
} }
} }
fun getMaximumBrightnessLevel(): Int { fun getMaximumBrightnessLevel(): Int {
return if (isTiramisuPlus()) { return if (isTiramisuPlus()) {
val characteristics = manager.getCameraCharacteristics(cameraId!!) val characteristics = manager.getCameraCharacteristics(cameraId)
characteristics.get(CameraCharacteristics.FLASH_INFO_STRENGTH_MAXIMUM_LEVEL) ?: MIN_BRIGHTNESS_LEVEL characteristics.get(CameraCharacteristics.FLASH_INFO_STRENGTH_MAXIMUM_LEVEL) ?: MIN_BRIGHTNESS_LEVEL
} else { } else {
MIN_BRIGHTNESS_LEVEL MIN_BRIGHTNESS_LEVEL

View File

@ -38,6 +38,14 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
fun newInstance(context: Context, cameraTorchListener: CameraTorchListener? = null) = MyCameraImpl(context, cameraTorchListener) fun newInstance(context: Context, cameraTorchListener: CameraTorchListener? = null) = MyCameraImpl(context, cameraTorchListener)
} }
private val cameraFlash: CameraFlash?
get() {
if (MyCameraImpl.cameraFlash == null) {
handleCameraSetup()
}
return MyCameraImpl.cameraFlash
}
init { init {
handleCameraSetup() handleCameraSetup()
stroboFrequency = context.config.stroboscopeFrequency stroboFrequency = context.config.stroboscopeFrequency
@ -62,7 +70,9 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
disableFlashlight() disableFlashlight()
} }
cameraFlash!!.unregisterListeners() cameraFlash.runOrToast {
unregisterListeners()
}
if (!tryInitCamera()) { if (!tryInitCamera()) {
return false return false
@ -104,7 +114,9 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
disableFlashlight() disableFlashlight()
} }
cameraFlash!!.unregisterListeners() cameraFlash.runOrToast {
unregisterListeners()
}
return if (isSOSRunning) { return if (isSOSRunning) {
stopSOS() stopSOS()
@ -131,8 +143,8 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
fun handleCameraSetup() { fun handleCameraSetup() {
try { try {
if (cameraFlash == null) { if (MyCameraImpl.cameraFlash == null) {
cameraFlash = CameraFlash(context, cameraTorchListener) MyCameraImpl.cameraFlash = CameraFlash(context, cameraTorchListener)
} }
} catch (e: Exception) { } catch (e: Exception) {
EventBus.getDefault().post(Events.CameraUnavailable()) EventBus.getDefault().post(Events.CameraUnavailable())
@ -157,8 +169,10 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
} }
try { try {
cameraFlash!!.initialize() cameraFlash.runOrToast {
cameraFlash!!.toggleFlashlight(true) initialize()
toggleFlashlight(true)
}
} catch (e: Exception) { } catch (e: Exception) {
context.showErrorToast(e) context.showErrorToast(e)
disableFlashlight() disableFlashlight()
@ -174,7 +188,9 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
} }
try { try {
cameraFlash!!.toggleFlashlight(false) cameraFlash.runOrToast {
toggleFlashlight(false)
}
} catch (e: Exception) { } catch (e: Exception) {
context.showErrorToast(e) context.showErrorToast(e)
disableFlashlight() disableFlashlight()
@ -198,14 +214,18 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
} }
fun releaseCamera() { fun releaseCamera() {
cameraFlash?.unregisterListeners() cameraFlash.runOrToast {
unregisterListeners()
}
if (isFlashlightOn) { if (isFlashlightOn) {
disableFlashlight() disableFlashlight()
} }
cameraFlash?.release() cameraFlash.runOrToast {
cameraFlash = null release()
}
MyCameraImpl.cameraFlash = null
cameraTorchListener = null cameraTorchListener = null
isFlashlightOn = false isFlashlightOn = false
@ -228,10 +248,14 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
handleCameraSetup() handleCameraSetup()
while (!shouldStroboscopeStop) { while (!shouldStroboscopeStop) {
try { try {
cameraFlash!!.toggleFlashlight(true) cameraFlash.runOrToast {
toggleFlashlight(true)
}
val onDuration = if (isStroboSOS) SOS[sosIndex++ % SOS.size] else stroboFrequency val onDuration = if (isStroboSOS) SOS[sosIndex++ % SOS.size] else stroboFrequency
Thread.sleep(onDuration) Thread.sleep(onDuration)
cameraFlash!!.toggleFlashlight(false) cameraFlash.runOrToast {
toggleFlashlight(false)
}
val offDuration = if (isStroboSOS) SOS[sosIndex++ % SOS.size] else stroboFrequency val offDuration = if (isStroboSOS) SOS[sosIndex++ % SOS.size] else stroboFrequency
Thread.sleep(offDuration) Thread.sleep(offDuration)
} catch (e: Exception) { } catch (e: Exception) {
@ -242,9 +266,11 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
// disable flash immediately if stroboscope is stopped and normal flash mode is disabled // disable flash immediately if stroboscope is stopped and normal flash mode is disabled
if (shouldStroboscopeStop && !shouldEnableFlashlight) { if (shouldStroboscopeStop && !shouldEnableFlashlight) {
handleCameraSetup() handleCameraSetup()
cameraFlash!!.toggleFlashlight(false) cameraFlash.runOrToast {
cameraFlash!!.release() toggleFlashlight(false)
cameraFlash = null release()
}
MyCameraImpl.cameraFlash = null
} }
shouldStroboscopeStop = false shouldStroboscopeStop = false
@ -271,22 +297,41 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
} }
fun getMaximumBrightnessLevel(): Int { fun getMaximumBrightnessLevel(): Int {
return cameraFlash!!.getMaximumBrightnessLevel() return cameraFlash.runOrToastWithDefault(MIN_BRIGHTNESS_LEVEL) {
getMaximumBrightnessLevel()
}
} }
fun getCurrentBrightnessLevel(): Int { fun getCurrentBrightnessLevel(): Int {
return cameraFlash!!.getCurrentBrightnessLevel() return cameraFlash.runOrToastWithDefault(DEFAULT_BRIGHTNESS_LEVEL) {
getCurrentBrightnessLevel()
}
} }
fun supportsBrightnessControl(): Boolean { fun supportsBrightnessControl(): Boolean {
return cameraFlash!!.supportsBrightnessControl() return cameraFlash.runOrToastWithDefault(false) {
supportsBrightnessControl()
}
} }
fun updateBrightnessLevel(level: Int) { fun updateBrightnessLevel(level: Int) {
cameraFlash!!.changeTorchBrightness(level) cameraFlash.runOrToast {
changeTorchBrightness(level)
}
} }
fun onCameraNotAvailable() { fun onCameraNotAvailable() {
disableFlashlight() disableFlashlight()
} }
private fun <T> CameraFlash?.runOrToastWithDefault(defaultValue: T, block: CameraFlash.() -> T): T {
return try {
this!!.block()
} catch (e: Exception) {
context.showErrorToast(e)
defaultValue
}
}
private fun CameraFlash?.runOrToast(block: CameraFlash.() -> Unit) = runOrToastWithDefault(Unit, block)
} }