Skip to content

Commit a71d9ff

Browse files
Merge pull request #1048 from navaronbracke/fix_ios_torch_mode
fix: provide correct initial torch state
2 parents c5e0289 + abaeadb commit a71d9ff

25 files changed

+256
-149
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
Bugs fixed:
44
* Fixed a crash when the controller is disposed while it is still starting. [#1036](https://github.com/juliansteenbakker/mobile_scanner/pull/1036) (thanks @EArminjon !)
5+
* Fixed an issue that causes the initial torch state to be out of sync.
6+
7+
Improvements:
8+
* Updated the lifeycle code sample to handle not-initialized controllers.
59

610
## 5.0.1
711

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,11 @@ class MyState extends State<MyStatefulWidget> with WidgetsBindingObserver {
103103
104104
@override
105105
void didChangeAppLifecycleState(AppLifecycleState state) {
106-
super.didChangeAppLifecycleState(state);
106+
// If the controller is not ready, do not try to start or stop it.
107+
// Permission dialogs can trigger lifecycle changes before the controller is ready.
108+
if (!controller.value.isInitialized) {
109+
return;
110+
}
107111
108112
switch (state) {
109113
case AppLifecycleState.detached:

android/src/main/kotlin/dev/steenbakker/mobile_scanner/MobileScanner.kt

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import androidx.camera.core.ExperimentalGetImage
1919
import androidx.camera.core.ImageAnalysis
2020
import androidx.camera.core.ImageProxy
2121
import androidx.camera.core.Preview
22+
import androidx.camera.core.TorchState
2223
import androidx.camera.core.resolutionselector.AspectRatioStrategy
2324
import androidx.camera.core.resolutionselector.ResolutionSelector
2425
import androidx.camera.core.resolutionselector.ResolutionStrategy
@@ -368,11 +369,22 @@ class MobileScanner(
368369
val height = resolution.height.toDouble()
369370
val portrait = (camera?.cameraInfo?.sensorRotationDegrees ?: 0) % 180 == 0
370371

372+
// Start with 'unavailable' torch state.
373+
var currentTorchState: Int = -1
374+
375+
camera?.cameraInfo?.let {
376+
if (!it.hasFlashUnit()) {
377+
return@let
378+
}
379+
380+
currentTorchState = it.torchState.value ?: -1
381+
}
382+
371383
mobileScannerStartedCallback(
372384
MobileScannerStartParameters(
373385
if (portrait) width else height,
374386
if (portrait) height else width,
375-
camera?.cameraInfo?.hasFlashUnit() ?: false,
387+
currentTorchState,
376388
textureEntry!!.id(),
377389
numberOfCameras ?: 0
378390
)
@@ -411,13 +423,16 @@ class MobileScanner(
411423
/**
412424
* Toggles the flash light on or off.
413425
*/
414-
fun toggleTorch(enableTorch: Boolean) {
415-
if (camera == null) {
416-
return
417-
}
426+
fun toggleTorch() {
427+
camera?.let {
428+
if (!it.cameraInfo.hasFlashUnit()) {
429+
return@let
430+
}
418431

419-
if (camera?.cameraInfo?.hasFlashUnit() == true) {
420-
camera?.cameraControl?.enableTorch(enableTorch)
432+
when(it.cameraInfo.torchState.value) {
433+
TorchState.OFF -> it.cameraControl.enableTorch(true)
434+
TorchState.ON -> it.cameraControl.enableTorch(false)
435+
}
421436
}
422437
}
423438

android/src/main/kotlin/dev/steenbakker/mobile_scanner/MobileScannerHandler.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class MobileScannerHandler(
7474
private var mobileScanner: MobileScanner? = null
7575

7676
private val torchStateCallback: TorchStateCallback = {state: Int ->
77+
// Off = 0, On = 1
7778
barcodeHandler.publishEvent(mapOf("name" to "torchState", "data" to state))
7879
}
7980

@@ -121,8 +122,8 @@ class MobileScannerHandler(
121122
}
122123
})
123124
"start" -> start(call, result)
124-
"torch" -> toggleTorch(call, result)
125125
"stop" -> stop(result)
126+
"toggleTorch" -> toggleTorch(result)
126127
"analyzeImage" -> analyzeImage(call, result)
127128
"setScale" -> setScale(call, result)
128129
"resetScale" -> resetScale(result)
@@ -167,7 +168,7 @@ class MobileScannerHandler(
167168
val position =
168169
if (facing == 0) CameraSelector.DEFAULT_FRONT_CAMERA else CameraSelector.DEFAULT_BACK_CAMERA
169170

170-
val detectionSpeed: DetectionSpeed = DetectionSpeed.values().first { it.intValue == speed}
171+
val detectionSpeed: DetectionSpeed = DetectionSpeed.entries.first { it.intValue == speed}
171172

172173
mobileScanner!!.start(
173174
barcodeScannerOptions,
@@ -182,7 +183,7 @@ class MobileScannerHandler(
182183
result.success(mapOf(
183184
"textureId" to it.id,
184185
"size" to mapOf("width" to it.width, "height" to it.height),
185-
"torchable" to it.hasFlashUnit,
186+
"currentTorchState" to it.currentTorchState,
186187
"numberOfCameras" to it.numberOfCameras
187188
))
188189
}
@@ -243,8 +244,8 @@ class MobileScannerHandler(
243244
mobileScanner!!.analyzeImage(uri, analyzeImageSuccessCallback, analyzeImageErrorCallback)
244245
}
245246

246-
private fun toggleTorch(call: MethodCall, result: MethodChannel.Result) {
247-
mobileScanner!!.toggleTorch(call.arguments == 1)
247+
private fun toggleTorch(result: MethodChannel.Result) {
248+
mobileScanner?.toggleTorch()
248249
result.success(null)
249250
}
250251

android/src/main/kotlin/dev/steenbakker/mobile_scanner/objects/MobileScannerStartParameters.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package dev.steenbakker.mobile_scanner.objects
33
class MobileScannerStartParameters(
44
val width: Double = 0.0,
55
val height: Double,
6-
val hasFlashUnit: Boolean,
6+
val currentTorchState: Int,
77
val id: Long,
88
val numberOfCameras: Int
99
)

example/ios/Runner.xcodeproj/project.pbxproj

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@
198198
9705A1C41CF9048500538489 /* Embed Frameworks */,
199199
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
200200
3DBCC0215D7BED1D9A756EA3 /* [CP] Embed Pods Frameworks */,
201+
BB0C8EA8DA81A75DE53F052F /* [CP] Copy Pods Resources */,
201202
);
202203
buildRules = (
203204
);
@@ -215,7 +216,7 @@
215216
isa = PBXProject;
216217
attributes = {
217218
BuildIndependentTargetsInParallel = YES;
218-
LastUpgradeCheck = 1430;
219+
LastUpgradeCheck = 1510;
219220
ORGANIZATIONNAME = "";
220221
TargetAttributes = {
221222
331C8080294A63A400263BE5 = {
@@ -317,6 +318,23 @@
317318
shellPath = /bin/sh;
318319
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
319320
};
321+
BB0C8EA8DA81A75DE53F052F /* [CP] Copy Pods Resources */ = {
322+
isa = PBXShellScriptBuildPhase;
323+
buildActionMask = 2147483647;
324+
files = (
325+
);
326+
inputFileListPaths = (
327+
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
328+
);
329+
name = "[CP] Copy Pods Resources";
330+
outputFileListPaths = (
331+
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
332+
);
333+
runOnlyForDeploymentPostprocessing = 0;
334+
shellPath = /bin/sh;
335+
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
336+
showEnvVarsInLog = 0;
337+
};
320338
C7DE006A696F551C4E067E41 /* [CP] Check Pods Manifest.lock */ = {
321339
isa = PBXShellScriptBuildPhase;
322340
buildActionMask = 2147483647;
@@ -495,7 +513,7 @@
495513
CURRENT_PROJECT_VERSION = 1;
496514
GENERATE_INFOPLIST_FILE = YES;
497515
MARKETING_VERSION = 1.0;
498-
PRODUCT_BUNDLE_IDENTIFIER = com.example.mobile-scanner.RunnerTests;
516+
PRODUCT_BUNDLE_IDENTIFIER = "com.example.mobile-scanner.RunnerTests";
499517
PRODUCT_NAME = "$(TARGET_NAME)";
500518
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
501519
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -513,7 +531,7 @@
513531
CURRENT_PROJECT_VERSION = 1;
514532
GENERATE_INFOPLIST_FILE = YES;
515533
MARKETING_VERSION = 1.0;
516-
PRODUCT_BUNDLE_IDENTIFIER = com.example.mobile-scanner.RunnerTests;
534+
PRODUCT_BUNDLE_IDENTIFIER = "com.example.mobile-scanner.RunnerTests";
517535
PRODUCT_NAME = "$(TARGET_NAME)";
518536
SWIFT_VERSION = 5.0;
519537
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -529,7 +547,7 @@
529547
CURRENT_PROJECT_VERSION = 1;
530548
GENERATE_INFOPLIST_FILE = YES;
531549
MARKETING_VERSION = 1.0;
532-
PRODUCT_BUNDLE_IDENTIFIER = com.example.mobile-scanner.RunnerTests;
550+
PRODUCT_BUNDLE_IDENTIFIER = "com.example.mobile-scanner.RunnerTests";
533551
PRODUCT_NAME = "$(TARGET_NAME)";
534552
SWIFT_VERSION = 5.0;
535553
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";

example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "1430"
3+
LastUpgradeVersion = "1510"
44
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"

example/ios/Runner/Info.plist

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
33
<plist version="1.0">
44
<dict>
5+
<key>CADisableMinimumFrameDurationOnPhone</key>
6+
<true/>
57
<key>CFBundleDevelopmentRegion</key>
68
<string>$(DEVELOPMENT_LANGUAGE)</string>
79
<key>CFBundleDisplayName</key>
@@ -28,6 +30,8 @@
2830
<string>This app needs camera access to scan QR codes</string>
2931
<key>NSPhotoLibraryUsageDescription</key>
3032
<string>This app needs photos access to get QR code from photo library</string>
33+
<key>UIApplicationSupportsIndirectInputEvents</key>
34+
<true/>
3135
<key>UILaunchStoryboardName</key>
3236
<string>LaunchScreen</string>
3337
<key>UIMainStoryboardFile</key>
@@ -47,9 +51,5 @@
4751
</array>
4852
<key>UIViewControllerBasedStatusBarAppearance</key>
4953
<false/>
50-
<key>CADisableMinimumFrameDurationOnPhone</key>
51-
<true/>
52-
<key>UIApplicationSupportsIndirectInputEvents</key>
53-
<true/>
5454
</dict>
5555
</plist>

example/lib/barcode_scanner_controller.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ class _BarcodeScannerWithControllerState
6363

6464
@override
6565
void didChangeAppLifecycleState(AppLifecycleState state) {
66-
super.didChangeAppLifecycleState(state);
66+
if (!controller.value.isInitialized) {
67+
return;
68+
}
6769

6870
switch (state) {
6971
case AppLifecycleState.detached:

example/lib/scanner_button_widgets.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,15 @@ class ToggleFlashlightButton extends StatelessWidget {
138138
}
139139

140140
switch (state.torchState) {
141+
case TorchState.auto:
142+
return IconButton(
143+
color: Colors.white,
144+
iconSize: 32.0,
145+
icon: const Icon(Icons.flash_auto),
146+
onPressed: () async {
147+
await controller.toggleTorch();
148+
},
149+
);
141150
case TorchState.off:
142151
return IconButton(
143152
color: Colors.white,

0 commit comments

Comments
 (0)