Skip to content

Commit ceed63a

Browse files
authored
Merge pull request #210 from esensar/fix/camera-null-crashes
Prevent null cameraId in CameraFlash
2 parents 1ce4c6e + 97b5389 commit ceed63a

File tree

2 files changed

+71
-25
lines changed

2 files changed

+71
-25
lines changed

app/src/main/kotlin/com/simplemobiletools/flashlight/helpers/CameraFlash.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ internal class CameraFlash(
1515
private var cameraTorchListener: CameraTorchListener? = null,
1616
) {
1717
private val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
18-
private var cameraId: String? = null
18+
private val cameraId: String
1919

2020
private val torchCallback = object : CameraManager.TorchCallback() {
2121
override fun onTorchModeChanged(cameraId: String, enabled: Boolean) {
@@ -28,10 +28,11 @@ internal class CameraFlash(
2828
}
2929

3030
init {
31-
try {
32-
cameraId = manager.cameraIdList[0] ?: "0"
31+
cameraId = try {
32+
manager.cameraIdList[0] ?: "0"
3333
} catch (e: Exception) {
3434
context.showErrorToast(e)
35+
"0"
3536
}
3637
}
3738

@@ -41,7 +42,7 @@ internal class CameraFlash(
4142
val brightnessLevel = getCurrentBrightnessLevel()
4243
changeTorchBrightness(brightnessLevel)
4344
} else {
44-
manager.setTorchMode(cameraId!!, enable)
45+
manager.setTorchMode(cameraId, enable)
4546
}
4647
} catch (e: Exception) {
4748
context.showErrorToast(e)
@@ -54,13 +55,13 @@ internal class CameraFlash(
5455

5556
fun changeTorchBrightness(level: Int) {
5657
if (isTiramisuPlus()) {
57-
manager.turnOnTorchWithStrengthLevel(cameraId!!, level)
58+
manager.turnOnTorchWithStrengthLevel(cameraId, level)
5859
}
5960
}
6061

6162
fun getMaximumBrightnessLevel(): Int {
6263
return if (isTiramisuPlus()) {
63-
val characteristics = manager.getCameraCharacteristics(cameraId!!)
64+
val characteristics = manager.getCameraCharacteristics(cameraId)
6465
characteristics.get(CameraCharacteristics.FLASH_INFO_STRENGTH_MAXIMUM_LEVEL) ?: MIN_BRIGHTNESS_LEVEL
6566
} else {
6667
MIN_BRIGHTNESS_LEVEL

app/src/main/kotlin/com/simplemobiletools/flashlight/helpers/MyCameraImpl.kt

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
3838
fun newInstance(context: Context, cameraTorchListener: CameraTorchListener? = null) = MyCameraImpl(context, cameraTorchListener)
3939
}
4040

41+
private val cameraFlash: CameraFlash?
42+
get() {
43+
if (MyCameraImpl.cameraFlash == null) {
44+
handleCameraSetup()
45+
}
46+
return MyCameraImpl.cameraFlash
47+
}
48+
4149
init {
4250
handleCameraSetup()
4351
stroboFrequency = context.config.stroboscopeFrequency
@@ -62,7 +70,9 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
6270
disableFlashlight()
6371
}
6472

65-
cameraFlash!!.unregisterListeners()
73+
cameraFlash.runOrToast {
74+
unregisterListeners()
75+
}
6676

6777
if (!tryInitCamera()) {
6878
return false
@@ -104,7 +114,9 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
104114
disableFlashlight()
105115
}
106116

107-
cameraFlash!!.unregisterListeners()
117+
cameraFlash.runOrToast {
118+
unregisterListeners()
119+
}
108120

109121
return if (isSOSRunning) {
110122
stopSOS()
@@ -131,8 +143,8 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
131143

132144
fun handleCameraSetup() {
133145
try {
134-
if (cameraFlash == null) {
135-
cameraFlash = CameraFlash(context, cameraTorchListener)
146+
if (MyCameraImpl.cameraFlash == null) {
147+
MyCameraImpl.cameraFlash = CameraFlash(context, cameraTorchListener)
136148
}
137149
} catch (e: Exception) {
138150
EventBus.getDefault().post(Events.CameraUnavailable())
@@ -157,8 +169,10 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
157169
}
158170

159171
try {
160-
cameraFlash!!.initialize()
161-
cameraFlash!!.toggleFlashlight(true)
172+
cameraFlash.runOrToast {
173+
initialize()
174+
toggleFlashlight(true)
175+
}
162176
} catch (e: Exception) {
163177
context.showErrorToast(e)
164178
disableFlashlight()
@@ -174,7 +188,9 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
174188
}
175189

176190
try {
177-
cameraFlash!!.toggleFlashlight(false)
191+
cameraFlash.runOrToast {
192+
toggleFlashlight(false)
193+
}
178194
} catch (e: Exception) {
179195
context.showErrorToast(e)
180196
disableFlashlight()
@@ -198,14 +214,18 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
198214
}
199215

200216
fun releaseCamera() {
201-
cameraFlash?.unregisterListeners()
217+
cameraFlash.runOrToast {
218+
unregisterListeners()
219+
}
202220

203221
if (isFlashlightOn) {
204222
disableFlashlight()
205223
}
206224

207-
cameraFlash?.release()
208-
cameraFlash = null
225+
cameraFlash.runOrToast {
226+
release()
227+
}
228+
MyCameraImpl.cameraFlash = null
209229
cameraTorchListener = null
210230

211231
isFlashlightOn = false
@@ -228,10 +248,14 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
228248
handleCameraSetup()
229249
while (!shouldStroboscopeStop) {
230250
try {
231-
cameraFlash!!.toggleFlashlight(true)
251+
cameraFlash.runOrToast {
252+
toggleFlashlight(true)
253+
}
232254
val onDuration = if (isStroboSOS) SOS[sosIndex++ % SOS.size] else stroboFrequency
233255
Thread.sleep(onDuration)
234-
cameraFlash!!.toggleFlashlight(false)
256+
cameraFlash.runOrToast {
257+
toggleFlashlight(false)
258+
}
235259
val offDuration = if (isStroboSOS) SOS[sosIndex++ % SOS.size] else stroboFrequency
236260
Thread.sleep(offDuration)
237261
} catch (e: Exception) {
@@ -242,9 +266,11 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
242266
// disable flash immediately if stroboscope is stopped and normal flash mode is disabled
243267
if (shouldStroboscopeStop && !shouldEnableFlashlight) {
244268
handleCameraSetup()
245-
cameraFlash!!.toggleFlashlight(false)
246-
cameraFlash!!.release()
247-
cameraFlash = null
269+
cameraFlash.runOrToast {
270+
toggleFlashlight(false)
271+
release()
272+
}
273+
MyCameraImpl.cameraFlash = null
248274
}
249275

250276
shouldStroboscopeStop = false
@@ -271,22 +297,41 @@ class MyCameraImpl private constructor(val context: Context, private var cameraT
271297
}
272298

273299
fun getMaximumBrightnessLevel(): Int {
274-
return cameraFlash!!.getMaximumBrightnessLevel()
300+
return cameraFlash.runOrToastWithDefault(MIN_BRIGHTNESS_LEVEL) {
301+
getMaximumBrightnessLevel()
302+
}
275303
}
276304

277305
fun getCurrentBrightnessLevel(): Int {
278-
return cameraFlash!!.getCurrentBrightnessLevel()
306+
return cameraFlash.runOrToastWithDefault(DEFAULT_BRIGHTNESS_LEVEL) {
307+
getCurrentBrightnessLevel()
308+
}
279309
}
280310

281311
fun supportsBrightnessControl(): Boolean {
282-
return cameraFlash!!.supportsBrightnessControl()
312+
return cameraFlash.runOrToastWithDefault(false) {
313+
supportsBrightnessControl()
314+
}
283315
}
284316

285317
fun updateBrightnessLevel(level: Int) {
286-
cameraFlash!!.changeTorchBrightness(level)
318+
cameraFlash.runOrToast {
319+
changeTorchBrightness(level)
320+
}
287321
}
288322

289323
fun onCameraNotAvailable() {
290324
disableFlashlight()
291325
}
326+
327+
private fun <T> CameraFlash?.runOrToastWithDefault(defaultValue: T, block: CameraFlash.() -> T): T {
328+
return try {
329+
this!!.block()
330+
} catch (e: Exception) {
331+
context.showErrorToast(e)
332+
defaultValue
333+
}
334+
}
335+
336+
private fun CameraFlash?.runOrToast(block: CameraFlash.() -> Unit) = runOrToastWithDefault(Unit, block)
292337
}

0 commit comments

Comments
 (0)