mobile_scanner icon indicating copy to clipboard operation
mobile_scanner copied to clipboard

Bug : Camera permission called again if user denied first one

Open EArminjon opened this issue 2 years ago • 10 comments

When user denied camera permission, system popup is called again.

camera_permission.webm

mobile_scanner : 3.0.0

Code :

import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';

void main() => runApp(const MaterialApp(home: MyHome()));

class MyHome extends StatelessWidget {
  const MyHome({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Flutter Demo Home Page')),
      body: SizedBox(
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.height,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              onPressed: () {
                Navigator.of(context).push(
                  MaterialPageRoute<dynamic>(
                    builder: (BuildContext context) => const BarcodeScannerWithController(),
                  ),
                );
              },
              child: const Text('MobileScanner with Controller'),
            ),
          ],
        ),
      ),
    );
  }
}

class BarcodeScannerWithController extends StatefulWidget {
  const BarcodeScannerWithController({super.key});

  @override
  _BarcodeScannerWithControllerState createState() => _BarcodeScannerWithControllerState();
}

class _BarcodeScannerWithControllerState extends State<BarcodeScannerWithController> with SingleTickerProviderStateMixin {
  BarcodeCapture? barcode;

  final MobileScannerController controller = MobileScannerController(
    torchEnabled: true,
    autoStart: true,
  );

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(controller.hashCode.toString()),
      ),
      backgroundColor: Colors.black,
      body: Stack(
        children: <Widget>[
          MobileScanner(
            startDelay: true,
            controller: controller,
            errorBuilder: (
              BuildContext context,
              MobileScannerException error,
              Widget? child,
            ) {
              return ScannerErrorWidget(error: error);
            },
            fit: BoxFit.contain,
            onDetect: (BarcodeCapture barcode) {
              setState(() {
                this.barcode = barcode;
              });
            },
          ),
        ],
      ),
    );
  }
}

class ScannerErrorWidget extends StatelessWidget {
  const ScannerErrorWidget({super.key, required this.error});

  final MobileScannerException error;

  @override
  Widget build(BuildContext context) {
    String errorMessage;

    switch (error.errorCode) {
      case MobileScannerErrorCode.controllerUninitialized:
        errorMessage = 'Controller not ready.';
        break;
      case MobileScannerErrorCode.permissionDenied:
        errorMessage = 'Permission denied';
        break;
      default:
        errorMessage = 'Generic Error';
        break;
    }

    return ColoredBox(
      color: Colors.black,
      child: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const Padding(
              padding: EdgeInsets.only(bottom: 16),
              child: Icon(Icons.error, color: Colors.white),
            ),
            Text(
              errorMessage,
              style: const TextStyle(color: Colors.white),
            ),
          ],
        ),
      ),
    );
  }
}

EArminjon avatar Feb 23 '23 10:02 EArminjon

Could be interesting to let us decide when call camera permission. This library can just display error when permission is missing :)

EArminjon avatar Feb 23 '23 10:02 EArminjon

I have the same, reproduced on the latest version, before updating I had 3.0.0-beta.1 and it worked fine

AlehSabadashGmail avatar Feb 24 '23 14:02 AlehSabadashGmail

reproduced only on android

AlehSabadashGmail avatar Feb 24 '23 14:02 AlehSabadashGmail

I have noticed the same behavior, but not only when denying but also when accepting. The system permission dialog shows up twice. However, in my case it only appears to happen on the emulator. Running the code on an actual device seems fine.

Possibly related to #419 and #407

richirisu avatar Mar 02 '23 01:03 richirisu

I have noticed the same behavior, but not only when denying but also when accepting. The system permission dialog shows up twice. However, in my case it only appears to happen on the emulator. Running the code on an actual device seems fine.

Possibly related to #419 and #407

It will happen on a physical device.

a1573595 avatar Mar 14 '23 03:03 a1573595

Hello, any news about this issue, even in 3.2.0 i go this issue only on Android only on denied case ?

BartholomeLB avatar Jun 06 '23 13:06 BartholomeLB

Any updates here? current version is 3.3.0

AlehSabadashGmail avatar Jul 12 '23 13:07 AlehSabadashGmail

For me it is working on Android if I change the didChangeAppLifecycleState inside the mobile_scanner to following:

switch (state) {
      case AppLifecycleState.resumed:
        if (_resumeFromBackground)
        _startScanner();
        break;
      case AppLifecycleState.paused:
        _resumeFromBackground = true;
        break;
      case AppLifecycleState.inactive:
        _resumeFromBackground = false; // I guess this line is dead code
        _controller.stop();
        break;
      case AppLifecycleState.detached:
        break;
    } 

additional info:

first time the methodchannel invokes the request channel which opens the popup that furthermore triggers the resumed lifecycle state and therefore restarts the controller (because _resumeFromBackground has still the initial value false). when denying the permission pop up it calls the popup again. didn't check why it doesnt end in a infinite loop afterwards (maybe something is happening in the channel then)...

so the first popup triggers a resumed state. when going to background it calls first the inactive, then the paused state and in the end the resumed.

androi7 avatar Aug 04 '23 11:08 androi7

Reproduced on Android mobile_scanner 3.5.2 go with camera 0.10.5

phuongnam195 avatar Dec 28 '23 10:12 phuongnam195

On Android 11 and below, the permission window will appear several times, and then begin endless attempts, which greatly slows down the application.

@juliansteenbakker

Holofox avatar Mar 12 '24 06:03 Holofox