Flutter - Denying permission on camera throws exception - android

Here is my initializeCamera code :
initializeCamera() async {
try {
final cameras = await availableCameras();
final firstCamera = cameras.first;
ContextManager.camera = firstCamera;
setState(() {
cameraAuthorized = true;
ContextManager.cameraAuthorized = cameraAuthorized;
});
} catch(e) {
ContextManager.camera = null;
setState(() {
cameraAuthorized = false;
ContextManager.cameraAuthorized = cameraAuthorized;
});
print(e);
}
}
Here is my initState code where I call the initializeCamera function and after that initialize the CameraController :
#override
void initState() {
super.initState();
initializeCamera().then((value) {
if (ContextManager.camera != null) {
setState(() {
_controller = CameraController(
ContextManager.camera,
ResolutionPreset.medium,
);
_initializeControllerFuture = _controller.initialize();
});
}
});
}
When I am running the code with flutter web from my computer browser I get this popup from my initializeCamera step :
When I click "allow" the rest of the code which is called in the then()
and especially _controller.initialize(), which initialize my camera on the device, is executed and the camera starts working. When I click "deny" another part of the code that I customed is run to display a message on the screen, in other words everything works fine.
When I'm running on the Android Emulator everything from my initializeCamera() function to _controller.initialize() is run without interruption until I get this popup :
Whether I choose "while using the app" or "only this time" the camera starts working and everything is ok. But when I click "deny" the app throws a CameraException.
I tried to wrap this line (which is causing the issue) :
_initializeControllerFuture = _controller.initialize()
in try/catch, and also specifying the name of the exception, but nothing worked.
What I don't get here, is that _controller.initialize() function is called before the popup show in the emulator, so the camera is initialized on the device before we can actually choose to deny/allow it.
While on the computer you actually get to choose whether you deny/allow the camera before the _controller.initialize() function is executed, which make perfect sense to me.
The ways it works on the emulator doesn't make any sense for me, if someone more knowledgeable could enlighten me, thanks.

Related

Flutter workmanager with home_widget working in debug and profile, but not in Android build APK

I have a todo app built in Flutter and intended only for Android. I built a home screen widget for it (using the home_widget package in Flutter) to allow users to see a list of tasks and check them off directly from the widget.
At midnight, the tasks should reset with the new tasks for the day (I used the workmanager package to accomplish this, although I also tried the android_alarm_manager_plus package, with the same results). All of this functionality is working perfectly in debug mode, and even in profile mode (I can't test it in release mode because, according to my understanding, that would remove services and thus the home_widget would not work; however, when I do the build, that doesn't seem to be the problem because the home widget still shows up). BUT! When I build the release APK and submit it to Google Play for internal testing, then download it onto my Pixel 7 (with no power saving modes on, as far as I'm aware), the midnight function does not run. :(
Here's the relevant code:
main_prod.dart
void main() async {
return mainGeneric('Prod Name', ProdFirebaseOptions.currentPlatform, Environment.prod);
}
main_generic.dart
/// Used for Background Updates using Workmanager Plugin
#pragma('vm:entry-point')
void workmanagerCallbackDispatcher() {
Workmanager().executeTask((taskName, inputData) {
if (taskName == 'widgetBackgroundUpdate') {
try {
return Future.wait<void>([
// This is a static Future<void> function from a helper class that resets
// the tasks; it seems to be working when I test it by itself, as well as
// in debug or profile mode.
MidnightService.resetTasks(),
]).then((value) {
return Future.value(true);
});
} catch(err) {
print(err.toString());
throw Exception(err);
}
}
return Future.value(true);
});
}
void _startBackgroundUpdate() async {
if (await MidnightService.shouldUpdateWorkManagerTasks()) {
(await SharedPreferences.getInstance()).setInt('midnight_tasks_update_version', Constants.MIDNIGHT_TASKS_UPDATE_VERSION);
await Workmanager().cancelAll();
DateTime now = DateTime.now();
int nowMillis = now.millisecondsSinceEpoch;
int midnightTonightMillis = DateTime(now?.year ?? 0, now?.month ?? 0, (now?.day ?? 0) + 1).millisecondsSinceEpoch;
int millisUntilMidnight = midnightTonightMillis - nowMillis;
await Workmanager().registerPeriodicTask('midnightUpdate', 'widgetBackgroundUpdate', initialDelay: Duration(milliseconds: millisUntilMidnight), frequency: Duration(days: 1));
}
}
void mainGeneric(String appName, FirebaseOptions firebaseOptions, Environment environment) async {
// Avoid errors caused by flutter upgrade.
WidgetsFlutterBinding.ensureInitialized();
Workmanager().initialize(workmanagerCallbackDispatcher, isInDebugMode: kDebugMode).then((_) => _startBackgroundUpdate());
...
// If this is the first time opening the app with widget functionality.
HomeWidget.getWidgetData<String>('todays_tasks_string', defaultValue: '').then((todaysTasksString) async {
if (todaysTasksString == '') {
List<Task> todaysTasks = await Repositories().taskRepository.getFocusedTasks();
await HomeWidgetUtils.setTodaysTasks(todaysTasks);
return true;
}
return false;
});
Firebase.initializeApp(
name: appName,
options: firebaseOptions,
).then((_) async {
...
});
HomeWidget.registerBackgroundCallback(homeWidgetBackgroundCallback);
runApp(AppConfig(
child: MyApp(),
environment: environment,
appTitle: appName,
));
}
// Called when doing background work initiated from home screen widget
#pragma('vm:entry-point')
Future<void> homeWidgetBackgroundCallback(Uri uri) async {
if (uri.host.startsWith('completetask_')) {
String todaysTasksString = await HomeWidgetUtils.updateTaskById(uri.host.split('_')[1], true);
await HomeWidget.saveWidgetData<String>('todays_tasks_string', todaysTasksString);
await HomeWidget.updateWidget(androidName: 'TodaysTasksWidgetProvider');
}
}
midnight_service.dart
class MidnightService {
...
static Future<bool> shouldUpdateWorkManagerTasks() async {
try {
final prefs = await SharedPreferences.getInstance();
int midnightTasksUpdateVersion = prefs.getInt('midnight_tasks_update_version');
return Constants.MIDNIGHT_TASKS_UPDATE_VERSION > midnightTasksUpdateVersion;
}
catch (e) { print(e); }
return true;
}
}
It might also be valuable to note that, when a user checks off a task from the home screen widget, sometimes the task takes a while to actually be checked off (and sometimes requires the app to be opened before it will execute). However, I figured this is just a slowness issue or something controlled by the OS that I can't do much about.
With all of that, my question is then, why is the workmanager not executing its midnight task?
I've been smashing my head against this for days, so any help and/or advice is greatly appreciated!!

Why wakeLock doesn't work in Samsung Internet

I have a React app that attempts to prevent a screen from sleeping when a component loads or on press of a button. For some reason it doesn't work in Samsung Internet. I does work in Chrome on Mac and in Chrome on Samsung phone. I can't find anything to suggest that this is a common problem. It looks like it is a supported feature. I do see the code being executed in logs, but the phone goes to sleep anyway. Is there anything that maybe should be enabled on the phone or in Samsung Internet settings of some sort?
Here is my implementation
async requestLock() {
Debugger.log('requesting wakeLock')
try {
if ('wakeLock' in navigator) {
this.wakeLock = await navigator.wakeLock.request('screen');
Debugger.log('wakeLock requested')
}
} catch (e) {
Debugger.log('wakeLock error');
}
}
async releaseLock() {
if (this.wakeLock) {
Debugger.log('releasing wakeLock')
await this.wakeLock.release();
Debugger.log('wakeLock released')
this.wakeLock = null;
}
}

Upload to Firestore in background with Flutter

I am using christocracy's flutter_background_geolocation package to build a crowdsensing app. This app relies on the geofencing function of the aforementioned package quite heavily. In the main function, I have implemented a callback function that is as follows (partial code):
void _onGeofence(bg.GeofenceEvent event) async {
await showGeofenceNotification(flutterLocalNotificationsPlugin,
title: "Geofence", body: "$event", id: notification_id);
if (action == "ENTER") {
// update certain variables
BarometerService.startBarometerService();
BarometerService.floorChange.listen((floorChanges) {
// update floor
updateDatabase();
});
}
else if (action == "EXIT") {
// update certain variables
BarometerService.stopBarometerService();
}
updateDatabase();
setState(() {
// update UI
});
}
The code works perfectly when the app is open and in focus. However, when in background, the barometer service stops. The updateDatabase() function is also not carried out as my Firestore console doesn't get updated.
Here is the code for updating the database:
Future updateUserState(String matric, bool inLWN, bool inVaughan, String activity, int confidence, int floor) async {
return await userCollection.document(uid).setData({
'matric': matric,
'inLWN': inLWN,
'inVaughan': inVaughan,
'activity': activity,
'confidence': confidence,
'floor': floor,
});
}
And here is the code for BarometerService (which uses Flutter sensors plugin):
import 'package:sensors/sensors.dart';
static startBarometerService() {
Stream<BarometerEvent> barometer10Events = barometerEvents.throttle(Duration(seconds:PERIOD_SECONDS));
subscription = barometer10Events.listen(onBarometer);
streamController = new StreamController();
}
How do I make my services run even when app is closed or terminated? I have implemented the same code in my headless callback functions (except updating UI), but nothing besides updating my (local) variables and showing local flutter notifications is working.
Headless task for reference:
void headlessTask(bg.HeadlessEvent headlessEvent) async {
print('[BackgroundGeolocation HeadlessTask]: $headlessEvent');
switch(headlessEvent.name) {
case bg.Event.GEOFENCE:
bg.GeofenceEvent geofenceEvent = headlessEvent.event;
onHeadlessGeofence(geofenceEvent);
print('- [Headless] GeofenceEvent: $geofenceEvent');
break;
case bg.Event.ACTIVITYCHANGE:
bg.ActivityChangeEvent event = headlessEvent.event;
onHeadlessActivityChange(event);
print('- [Headless] ActivityChangeEvent: $event');
break;
}
}
onHeadlessGeofence is almost identical to the callback _onGeofence, besides the setState().
The full code can be found here

Meteor.call doesn’t work on android App

I created a simple app using Meteor 1.3, which has only one method. It works like that: When a button is clicked, the method is invoked - it calculates a specific value and returns the result.
The app works perfectly on the localhost server, but when I launch it on my device with "meteor run android-device", it cannot access the method (simply opens the app, but nothing happens when I press a button.
Do you know how I could resolve this?
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { ReactiveDict } from 'meteor/reactive-dict';
import './main.html';
Template.check.onCreated(function checkOnCreated() {
this.state = new ReactiveDict();
});
Template.check.events({
'click .checkit'(event, instance) {
Meteor.call('code.check', function(error, result){
if(error){
console.log('Error from the client side!');
} else {
instance.state.set('fett', result.titles[0]);
}
});
},
});
Template.check.helpers({
fett() {
const instance = Template.instance();
if (instance.state.get('fett')) {
return instance.state.get('fett');
} else {
return 'Value still not known...'
}
},
});
Ensure your smartphone's WiFi is turned on and it connected to the same WiFi network as you computer where meteor app is running. Then everything should work fine.
Also, I recommend to use chrome://inspect feature (more info here) in order to debug your app on Android. Then, you will be able quickly investigate any problems with mobile app.

Cordova: (ion-google-place) google map api callback not working on Android Phone

i am using ion-google-place directive in my ionic project and when i run it in the ripple I can see that this directive works as expected, however when i deploy it on my Android phone the search bar comes up but when i type no drop down is shown.
I tried to debug the code and can see the issue to be around the following code:
var geocoder = new google.maps.Geocoder();
geocoder.geocode(req, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
scope.$apply(function () {
scope.locations = results;
});
} else {
// #TODO: Figure out what to do when the geocoding fails
console.log("error getting google place...");
}
});
the callback function is never called when running within the android phone, however from ripple its working.
Any ideas as to what I may be missing ?
EDIT 1:
I created a Blank Cordova project and added the refrences to angular and google map. Then added a button and added a ng-onclick to that button as below
$scope.onButtonClick = function () {
var api = new google.maps.places.AutocompleteService();
api.getPlacePredictions({ input: "Banga" }, function (results, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
console.log("google place... success");
} else {
// #TODO: Figure out what to do when the geocoding fails
console.log("error getting google place...");
}
});
Now I see that google is not defined when debugging the Android Phone, where as same when being debugged in ripple, it is working.
is there something on the phone that can prevent the maps from being available to the app?
Regards
Kiran

Categories

Resources