I am developing a custom object detection app for Android using the camera package in conjunction with tflite. When the screen loads, it asks the user for camera and microphone permission using the permission_handler package. I'm also using a ChangeNotifier class to store the results after asking the user for permission. Then, depending on whether the user accepts these conditions, I'm conditionally rendering widgets. Now, there are a few cases here:
a. Neither is granted → request for both permission if it isn't permanently denied and if it is then ask the user to manually grant it from settings
b. Permission for the camera is granted, but the user denied mic permission → request for mic permission if it isn't permanently denied and if it is then ask the user to manually grant it from settings
c. Permission for the mic is granted, but camera permission is denied → request for camera permission if it isn't permanently denied and if it is then ask the user to manually grant it from settings
d. Neither is granted → request for both permission if they aren't permanently denied and if they are then ask the user to manually grant them from settings
Here is my current implementation.
https://codeshare.io/X8eKWE
The problem is that even when the user grants both the permissions, it shows:
'Camera permission was denied!', 'Request camera permission' widget.
So, how can I handle all four different cases in a more elegant way?
class _LiveFeedState extends State<LiveFeed> with WidgetsBindingObserver {
Widget? errWidget;
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
switch (state) {
case AppLifecycleState.resumed:
log("App Resumed");
_checkCameraPermissionStatus();
break;
case AppLifecycleState.inactive:
log("App Inactive");
break;
case AppLifecycleState.paused:
log("App Paused");
break;
case AppLifecycleState.detached:
log("App Detached");
break;
}
}
#override
void dispose() {
super.dispose();
WidgetsBinding.instance.removeObserver(this);
}
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
Widget bodyWidget() {
return CameraFeed...;
}
Widget permissionScreen(Function onPressedHandler, String titleText, String buttonText) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(titleText),
ElevatedButton(
onPressed: () {
onPressedHandler();
},
child: Text(buttonText)),
],
);
}
Future<void> _checkCameraPermissionStatus() async {
var status = await Permission.camera.request().then((value) => value);
switch (status) {
case PermissionStatus.granted:
errWidget = await _checkMicPermissionStatus();
setState(() {});
break;
case PermissionStatus.denied:
setState(() {
errWidget = permissionScreen(_checkCameraPermissionStatus, 'Camera permission was denied!', 'Request camera permission');
});
break;
case PermissionStatus.permanentlyDenied:
setState(() {
errWidget = permissionScreen(openAppSettings, 'Camera permission was permanently denied! Open app setings and manually grant permission', 'Open app settings');
});
break;
default:
errWidget = await _checkMicPermissionStatus();
setState(() {});
break;
}
}
Future<Widget> _checkMicPermissionStatus() async {
var status = await Permission.microphone.request().then((value) => value);
switch (status) {
case PermissionStatus.granted:
return bodyWidget();
case PermissionStatus.denied:
return permissionScreen(_checkCameraPermissionStatus, 'Microphone permission was denied!', 'Request Microphone permission');
case PermissionStatus.permanentlyDenied:
return permissionScreen(openAppSettings, 'Microphone permission was permanently denied! Open app setings and manually grant permission', 'Open app settings');
default:
return bodyWidget();
}
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: isPortrait
? AppBar(
title: const Text("SpotHole"),
)
: null,
body: FutureBuilder(
future: Future.wait([Permission.camera.status, Permission.microphone.status]),
builder: (BuildContext context, AsyncSnapshot<List<PermissionStatus>> snapshot) {
if (snapshot.hasData) {
if (snapshot.data![0] == PermissionStatus.granted ||
snapshot.data![0] == PermissionStatus.limited ||
snapshot.data![1] == PermissionStatus.granted ||
snapshot.data![1] == PermissionStatus.limited) {
return bodyWidget();
} else {
if (errWidget != null) {
return errWidget!;
} else {
if (snapshot.data![0] != PermissionStatus.granted || snapshot.data![0] != PermissionStatus.limited) {
return permissionScreen(_checkCameraPermissionStatus, 'Camera permission was denied!', 'Request camera permission');
} else {
return permissionScreen(_checkCameraPermissionStatus, 'Microphone permission was denied!', 'Request Microphone permission');
}
}
}
} else {
return const CircularProgressIndicator.adaptive();
}
},
)));
}
}
Related
I am trying to access storage on an Android emulator from Flutter.
Here is the code that I'm testing it with:
void test() async {
PermissionStatus storageStatus = await Permission.storage.request();
if (storageStatus == PermissionStatus.granted) {
print("granted");
}
if (storageStatus == PermissionStatus.denied) {
print("denied");
}
if (storageStatus == PermissionStatus.permanentlyDenied) {
openAppSettings();
}
}
I have included the "android.permission.WRITE_EXTERNAL_STORAGE" permission in the AndroidManifest.xml.
I have tried giving permissions for Camera and it worked, but it doesn't work for storage.
When I check for the storages permission status it is permanently denied, and when app's settings open it says "No permissions requested".
I have tried running "flutter clean" which seems to be necessary when updating the Manifest.
I have tried uninstalling from the phone and reinstalling the app
How do I fix it?
once try to do this.
Add in your manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
for requesting permission.
Future<bool> requestPermission(Permission permission) async {
if (await permission.isGranted) {
return true;
} else {
var result = await permission.request();
if (result == PermissionStatus.granted) {
return true;
}
}
return false;
}
for checking permission also you can change dialog text as per your need
Future<bool> checkPermission() async {
///For Check permission..
if (Platform.isAndroid ? !await requestPermission(Permission.storage) && !await requestPermission(Permission.manageExternalStorage) : !await requestPermission(Permission.storage)) {
await Get.dialog(CupertinoAlertDialog(
title: const Text("Photos & Videos permission"),
content: const Text(" Photos & Videos permission should be granted to connect with device, would you like to go to app settings to give Bluetooth & Location permissions?"),
actions: <Widget>[
TextButton(
child: const Text('No thanks'),
onPressed: () {
Get.back();
}),
TextButton(
child: const Text('Ok'),
onPressed: () async {
Get.back();
await openAppSettings();
})
],
));
return false;
} else {
return true;
}
}
Use like this
I hope these things solve your issue.
I am currently using the latest geolocator that is 'geolocator: ^9.0.1'and for some reason am not able to get any data from the position function when i run
bool isLoc = await Geolocator.isLocationServiceEnabled();
print(isLoc);
The result is true which i think means the location services are all enabled but when i run
Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.best);
print('position');
nothing is been returned i have tried all the accuracy values low, high, best,lowest, medium am really confused at what could be wrong i have also try it in the initState and also using a *button
Here is the full dart code
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
class GeoLoc extends StatefulWidget {
const GeoLoc({Key? key}) : super(key: key);
#override
State<GeoLoc> createState() => _GeoLocState();
}
class _GeoLocState extends State<GeoLoc> {
#override
void initState() {
super.initState();
getLoc();
}
#override
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(onPressed: () {
getLoc();
},
child: const Text('Get Location'),
),
],
);
}
getLoc() async{
bool isLoc = await Geolocator.isLocationServiceEnabled();
print(isLoc);
Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
print(position);
}
}
Below is your code modified, pls try it. you forget to ask for geolocation permission
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
class GeoLoc extends StatefulWidget {
const GeoLoc({Key? key}) : super(key: key);
#override
State<GeoLoc> createState() => _GeoLocState();
}
class _GeoLocState extends State<GeoLoc> {
#override
void initState() {
super.initState();
getLoc()
.then((value) => print("Location: " + value.toJson().toString()));
}
#override
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(onPressed: () {
getLoc()
.then((value) => print("Location: " + value.toJson().toString()));
},
child: const Text('Get Location'),
),
],
);
}
getLoc() async{
bool serviceEnabled;
LocationPermission permission;
// Test if location services are enabled.
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
// Location services are not enabled don't continue
// accessing the position and request users of the
// App to enable the location services.
Geolocator.openLocationSettings();
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
// Permissions are denied, next time you could try
// requesting permissions again (this is also where
// Android's shouldShowRequestPermissionRationale
// returned true. According to Android guidelines
// your App should show an explanatory UI now.
Geolocator.openAppSettings();
}
}
if (permission == LocationPermission.deniedForever) {
// Permissions are denied forever, handle appropriately.
return Future.error(
'Location permissions are permanently denied, we cannot request permissions.');
}
// When we reach here, permissions are granted and we can
// continue accessing the position of the device.
return await Geolocator.getCurrentPosition();
}
}
Also make sure you have below permission in your AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
I want to open the appropriate window depending on whether the user is authenticated or not.
But now an error appears for a second
[core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()
and then the map does not open even though the user is authenticated.
"start" it is a variable that is initialRoute
Here is my code.
void main() => runApp(App());
String start = "";
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
Firebase.initializeApp().whenComplete((){
FirebaseAuth.instance
.authStateChanges()
.listen((User user) {
if (user == null) {
print('User is currently signed out!');
start = '/';
} else {
print('User is signed in!');
start = '/map/${FirebaseAuth.instance.currentUser.uid}';
}
});
});
WidgetsFlutterBinding.ensureInitialized();
return FutureBuilder(
builder: (context, snapshot) {
return MyApp();
}
);
}
}
Initialize your default firebase app like below;
Future<void> initializeDefault() async {
FirebaseApp app = await Firebase.initializeApp();
assert(app != null);
setState(() {
loading = false;
}
);
print('Initialized default app $app');
}
#override
void initState() {
initializeDefault();
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(statusBarColor: Colors.transparent));
super.initState();
}
I'm writing a Flutter Application which checks if My device is connected to another device, +-Blutooth device or no all.
What I find in Flutter documentation wasn't able to help me because I check first if the bluetooth is opened or not. I ask the user for it as it show in the code but I can't check if the device is connected. I did it with wifi but with bluetooth I can't.
#override
Widget build(BuildContext context) {
return MaterialApp(
color: Colors.lightBlue,
home: StreamBuilder<BluetoothState>(
stream: FlutterBlue.instance.state,
initialData: BluetoothState.unknown,
builder: (c, snapshot) {
final state = snapshot.data;
if (state == BluetoothState.off)
// ignore: missing_return
return Bluetoth();
else return Find();
}),
);
}
// open bluetooth if closed
class BluetothState extends State<Bluetoth>
{
void initState(){
super.initState();
aa();
}
Future aa() async {
// async lambda seems to not working
print('ccc');
await FlutterBluetoothSerial.instance.requestEnable();
}
class _FindState extends State<Find> {
//check bluetooth connectivity
}
Use the connectedDevices future:
var _flutterBlue = FlutterBlue.instance;
_flutterBlue.connectedDevices.then((value) {
//Do your processing
});
I am new to Flutter and Firebase and am working on an authentication app.
How do I make the app go to the HomePage if a user is signed in already or go to the login page if no user is signed in?
Forgive my rusty code.
FirebaseAuth auth = Firebase.instance;
void main() {
Future<bool> home() async {
if (await auth.currentUser() == null) {
return false;
}
return true;
}
runApp(
new MaterialApp(
title: 'DASH',
home: home() == null ? LoginScreen() : HomeScreen(),
theme: DashTheme.theme,
color: DashTheme.white,
routes: <String, WidgetBuilder>{
// Set routes for using the Navigator.
'/home': (BuildContext context) => new HomeScreen(),
'/login': (BuildContext context) => new LoginScreen(),
},
),
);
}
I'm using Future Builder
Widget _getLandingPage() {
return FutureBuilder<FirebaseUser>(
future: FirebaseAuth.instance.currentUser(),
builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot){
if (GlobalStore.state.userConfig != null && GlobalStore.state.userConfig.isDisplayIntroScreen == true) {
return routes.buildPage('intro_screen', null);
}
if (snapshot.hasData) {
return routes.buildPage('main', null);
} else {
return routes.buildPage('auth', null);
}
},);
home: _getLandingPage(),
While I never wrote anything in the Dart language, I can see that you wrote some good beginning. If we take a look at this line:
home: home() == null ? LoginScreen() : HomeScreen(),
You are checking in home() if the user is logged in. However, you are checking if the return value is null while the returned object of the method is Future<bool>. (This means that in this case the condition is always false).
Also note that this method is async. That means that you will not really know when this method is actually done executing. (This will be some moment in the future).
That being said, you should display an initial page once the app starts up. Then you should run and check the return value of the future method. According to the docs (https://www.dartlang.org/tutorials/language/futures) this can be done like this:
// Call this after the initialization of your app and pages
final future = home();
future.then((isLoggedIn) => ); // Inside here you need to do a navigation to the homepage or loginpage
A little modification is required in your code.
Instead of checking the current user in the main function like that, what you can do is check user in the initState() function.
#override
void initState()
{
super.initState();
final FirebaseAuth _auth = FirebaseAuth.instance;
if(_auth.currentUser() == null)
{
Navigator.of(context).pushNamedAndRemoveUntil("/LoginScreen" , (Route<dynamic> route) => false);
}
else
{
Navigator.of(context).pushNamedAndRemoveUntil("/HomeScreen" , (Route<dynamic> route) => false);
}
}
pushNamedAndRemoveUntil is used if you don't want the user to go back to the previous scene or route.
You can Read about Navigation in flutter here. And use the one you need.
Thanks alot for all your answers.
I was checking up on the answers and this is what I came across.
I don't know if it's the right thing to do but it is actually working.
Here is the code:
Widget _getLandingPage() {
return StreamBuilder<FirebaseUser>(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (BuildContext context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.providerData.length == 1) {
return snapshot.data.isEmailVerified ? HomeScreen() : VerifyEmailScreen();
} else {
return HomeScreen();
}
} else {
return LoginScreen();
}
},
);
}
home: _getLandingPage(),