Flex mobile: remove GeolocationEvent.UPDATE does not work - android

I can't seem to remove the listener for the update event for geolocation on Android.
I wanna stop the Geolocation on deactivate:
NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, onAppDeactivate);
private function onAppDeactivate(e:Event):void {
if (Geolocation.isSupported) {
if (geolocation != null) {
geolocation.removeEventListener(GeolocationEvent.UPDATE, onGeolocationUpdate);
geolocation.setRequestedUpdateInterval(0);
geolocation = null;
}
}
}
I started with just removing the listener, but since that didn't work I also tried removing the geolocation all together. Still no luck..
Any hints?

I had an app that uses Geolocation too, and if what you want is to save the battery from draining fast, you have to call the geolocation.setRequestedUpdateInterval(INTERVAL_MILLIS) method with a high value for INTERVAL_MILLIS (in my case i use 60000 that is 1 min).
But as the (documentation) says, the OS will decide the update interval for the GPS, ant the value we pass serves a a "hint" to the update interval.
And specifically on Android, the GPS icon will stay on as long as you have the GPS enabled (and it will consume power) but will no drain you battery fast as the update interval will be high.
So the best thing you can do is actually request a large update interval when you app deactivates.

Related

Flutter Dart - isolate stops working when screen is off

I have code to refresh data from server which I need to run even when screen is off. I tried to do this with an isolate:
static void isolateFunc(SendPort mainSendPort) async{
String _answer = "";
while(true){
Socket socket = await Socket.connect(ipAddress, port, timeout: Duration(seconds: 5));
socket.add(utf8.encode("connection test"));
socket.listen((List<int> event) {
_answer = utf8.decode(event);
});
socket.close();
await Future.delayed(Duration(seconds: 5));
}
}
This works fine when screen is on. But after switching off the screen it refreshs maybe for 5 times normally, then it refreshs for a few times each 30 sesconds(even when the delay is set to 5 seconds) and then it just stops. I am calling the isolate from initState like this:
#override
void initState() {
super.initState();
anotherRefresher();
ReceivePort recievePort = ReceivePort();
Isolate.spawn(isolateFunc, recievePort.sendPort);
}
Battery optimalisation in android settings is off. I do not understand this :/ Any ideas how to deal with this please?
After some time I found that, there is no way how to keep running dart code in the background without setting it as background or foreground process. Both Android and iOS will always restrict your code to increase battery life. Even turning off battery optimisation will not help. So to keep dart code running even when screen is off, you need to set up background or foreground process. For this you can do some platform native coding and connect it through platform channels or use plugins. Since I don't know Swift or Kotlin, I decided to find some plugins. I have tried more of them and after some time I can say that plugin flutter_background_service is one of the best. Or based on your needs you can find another plugins or try to code it by yourself. Wish you good luck :)

LocationAvailability No Location Available

Google's FusedLocationProviderApi for Android was recently deprecated within the past few months, with FusedLocationProviderClient being its successor so I recently updated the location APIs used in my client's app to use the new ones.
Every time onLocationAvailability is fired in LocationCallback I notify the user when locationAvailability.isLocationAvailable() returns false, but it appears that this condition occurs more often than I expected on some devices. I run these location updates inside a foreground Service and it is crucial that these location updates remain consistent. Is there a way to determine the cause of this failure so
We don't indicate any false positives to the end-user
We can try to fix the issue or at least report to the end-user what they should do?
It appears to me that either the deprecated APIs provide more insight into these issues since it was used in conjunction with GoogleApiClient or perhaps I'm missing some smaller details.
I went through the same issue. And after three days of trying things out, I got to work on it out.
I also had to collect a location in a foreground state like you, and if the foreground service was destroyed, I had to unregister.
The first mistake I made was not to guarantee that removeLocationUpdates would be run on the same thread as the requestLocationUpdates. Actually, it doesn't have to be the same thread, but after a requestLocationUpdates, you must call removeLocationUpdates to make the next requestLocationUpdates valid. To ensure this, it is much easier to work on the same thread.
For example:
private fun FusedLocationProviderClient.requestLocation(
request: LocationRequest
): Single<LocationResult> {
return Single.create<LocationResult> { emitter ->
requestLocationUpdates(request, object : LocationCallback() {
override fun onLocationResult(result: LocationResult?) {
removeLocationUpdates(object : LocationCallback() {})
.addOnCompleteListener {
if (emitter.isDisposed) {
info("onLocationResult called after disposing.")
return#addOnCompleteListener
}
if (result != null && result.locations.isNotEmpty()) {
onSuccess(result)
} else {
onError(RuntimeException("Invalid location result"))
}
}
}
private fun onError(error: Exception) {
if (!emitter.isDisposed) {
emitter.onError(error)
}
}
private fun onSuccess(item: LocationResult) {
if (!emitter.isDisposed) {
emitter.onSuccess(item)
}
}
}, Looper.getMainLooper())
}
}
As the code suggests, I have attracted Single's emitter to the addOnCompleteListener in removeLocationUpdates to ensure the call of removeLocationUpdates behind the requestLocationUpdates. Without RxJava, of course, it would be easier to implement.
The second mistake I made was the wrong interval setting in LocationRequest. According to the doc:
This method sets the rate in milliseconds at which your app prefers to receive location updates. Note that the location updates may be somewhat faster or slower than this rate to optimize for battery usage, or there may be no updates at all (if the device has no connectivity, for example).
The explanation is unkind but ultimately, if you call requestLocationUpdates once, you must have a Location update event triggered by interval before the next requestLocationUpdates. Finding this bug was the hardest.
The third mistake I made was to set the wrong priority in LocationRequest. In API 10 and below, it was not PRIORITY_BALANCED_POWER_ACCURACY but it was resolved by using PRIORITY_HIGH_ACCURACY. In this case, I have only tested on the emulator, so the actual device may have different results. I guess PRIORITY_BALANCED_POWER_ACCURACY doesn't seem to work properly because the emulator doesn't provide Bluetooth hardware.
So my LocationRequest looks like:
LocationRequest.apply {
priority = PRIORITY_HIGH_ACCURACY
interval = 10000L
}
I hope the three mistakes and solutions I made is helpful to you!
As official documentation says:
onLocationAvailability Called when there is a change in the
availability of location data. When isLocationAvailable() returns
false you can assume that location will not be returned in
onLocationResult(LocationResult) until something changes in the
device's settings or environment. Even when isLocationAvailable()
returns true the onLocationResult(LocationResult) may not always be
called regularly, however the device location is known and both the
most recently delivered location and getLastLocation(GoogleApiClient)
will be reasonably up to date given the hints specified by the active
LocationRequests.
So this method does not provide information about reason.
We don't indicate any false positives to the end-user
Currently I just ignore result of this method because it returns false too often, and then again true, and so on.
We can try to fix the issue or at least report to the end-user what they should do?
Check if Location Services are enabled (using LocationManager.isProviderEnabled())
Check if you have permissions, request them if needed (docs)
I filter false positives of locationAvailability.isLocationAvailable() by calling this piece of code, which checks if location service is enabled.
fun isLocationEnabled(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val lm = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
lm.isLocationEnabled
} else {
val mode = Settings.Secure.getInt(
context.contentResolver, Settings.Secure.LOCATION_MODE,
Settings.Secure.LOCATION_MODE_OFF
)
mode != Settings.Secure.LOCATION_MODE_OFF
}
}
override fun onLocationAvailability(p0: LocationAvailability?) {
if (isLocationEnabled().not()) {
locationUpdateSubject.failed(LocationAvailabilityError)
}
}
as Google docs says:
When isLocationAvailable() returns false you can assume that location
will not be returned in onLocationResult(LocationResult) until
something changes in the device's settings or environment.
So you can assume that location may be not available not only because of disabled location settings, but because of signal strength, or maybe satellites are not visible or something else, it just indicates that you will not receive location updates until something changes. You can show user notification about it with something like "We can't get your location, try enable location settings"
I've faced same issue and same time I saw that location services has been enabled on the device and my ap had allowed permissions from user.
I still saw
com.google.android.gms.location.LocationCallback#onLocationAvailability LocationAvailability[isLocationAvailable: false]
The issue was that there is additional preference inside Location item on the phone. We have to choose Battery saving/High accuracy option. Please check out the screenshot provided:

Change the period of a periodic task in Firebase JobDispatcher?

I was using GCM network manager, but then I heard that Firebase JobDispatcher includes GCM plus other features so I'm trying to use that.
I have successfully programmed a periodic task and it works fine, but the problem is that I need the period to change and not be fixed from the beginning.
The reason for that is, I'm using an activity recognition service and I want the next time the JobDispatcher executes the periodic task to be based on the detected current activity. For example if you're walking, the next time the task is triggered is after 30 minutes, while if you're in a car then the period is 5 minutes (mainly because if you're in a car it's more likely that your phone will provide different location values in a short while compared to when you're on foot).
This is the way I program the periodic task, as you can see I'm setting a fixed value, I want to know if the service that is triggered by this task can provide a feedback that'll change the period of the task.
final Builder builder = jobDispatcher.newJobBuilder()
.setTag(form.tag.get())
.setRecurring(form.recurring.get())
.setLifetime(form.persistent.get() ? Lifetime.FOREVER : Lifetime.UNTIL_NEXT_BOOT)
.setService(DemoJobService.class)
.setTrigger(Trigger.executionWindow(
form.getWinStartSeconds(), form.getWinEndSeconds()))
.setReplaceCurrent(form.replaceCurrent.get())
.setRetryStrategy(jobDispatcher.newRetryStrategy(
form.retryStrategy.get(),
form.getInitialBackoffSeconds(),
form.getMaximumBackoffSeconds()));
if (form.constrainDeviceCharging.get()) {
builder.addConstraint(Constraint.DEVICE_CHARGING);
}
if (form.constrainOnAnyNetwork.get()) {
builder.addConstraint(Constraint.ON_ANY_NETWORK);
}
if (form.constrainOnUnmeteredNetwork.get()) {
builder.addConstraint(Constraint.ON_UNMETERED_NETWORK);
}
To do this you'd need to have your onStartJob in DemoJobService.class cancel itself using your tag that you've saved in SharedPrefs / elsewhere (form.tag.get() in your example):
FirebaseJobDispatcher(GooglePlayDriver(context)).cancel(yourTag)
It can then reschedule the job with the updated parameters. Unfortunately there's currently no way to edit jobs, they must be cancelled and recreated!

Detecting Mock Location Not Working (Android)

I'm trying to set some protection against people using mock locations to manipulate my app. I realise that it's impossible to prevent 100%... I'm just trying to do what I can.
The app uses Google location services (part of play services) in its main activity.
The onLocationChanged() method is:
public void onLocationChanged(Location location) {
this.mCurrentLocation = location;
if (Build.VERSION.SDK_INT > 17 && mCurrentLocation.isFromMockProvider()) {
Log.i(TAG, "QQ Location is MOCK");
// TODO: add code to stop app
// otherwise, currently, location will never be updated and app will never start
} else {
Double LAT = mCurrentLocation.getLatitude();
Double LON = mCurrentLocation.getLongitude();
if ((LAT.doubleValue() > 33.309171) || (LAT.doubleValue() < 33.226442) || (LON.doubleValue() < -90.790165) || (LON.doubleValue() > -90.707081)) {
buildAlertMessageOutOfBounds();
} else if (waiting4FirstLocationUpdate) {
Log.i(TAG, "YYY onLocationChanged() determines this is the FIRST update.");
waiting4FirstLocationUpdate = false;
setContentView(R.layout.activity_main);
startDisplayingLists();
}
}
}
The location services work perfectly and all is well with the app in general, but when I run the app in an emulator with Android Studio (Nexus One API 23), and I set the location using extended controls (mock), the app just continues to work as normal, and so it seems that the condition:
if (Build.VERSION.SDK_INT > 17 && mCurrentLocation.isFromMockProvider())
Is returning false.
This doesn't make any sense to me. Does anyone know why this would happen?
Thanks!
The short answer: .isFromMockProvider is unreliable. Some fake locations are not properly detected as such.
I have spent an extensive amount of time researching this and written a detailed blog post about it.
I also spent time to find a solution to reliably suppress mock locations across all recent/relevant Android versions and made a utility class, called the LocationAssistant, that does the job.
In a nutshell (using the aforementioned LocationAssistant):
Set up permissions in your manifest and Google Play Services in your gradle file.
Copy the file LocationAssistant.java to your project.
In the onCreate() method of your Activity, instantiate a LocationAssistant with the desired parameters. For example, to receive high-accuracy location updates roughly every 5 seconds and reject mock locations, call new LocationAssistant(this, this, LocationAssistant.Accuracy.HIGH, 5000, false). The last argument specifies that mock locations shouldn't be allowed.
Start/stop the assistant with your Activity and notify it of permission/location settings changes (see the documentation for details).
Enjoy location updates in onNewLocationAvailable(Location location). If you chose to reject mock locations, the callback is only invoked with non-mock locations.
There are some more methods to implement, but essentially this is it. Obviously, there are some ways to get around mock provider detection with rooted devices, but on stock, non-rooted devices the rejection should work reliably.

How to get user position by GPS in Sencha

I'm trying to get user position in Sencha Touch 2:
var geo = new Ext.util.Geolocation({
autoUpdate: true,
allowHighAccuracy: true,
listeners: {
locationupdate: function(geo) {
lat = geo.getLatitude();
lon = geo.getLongitude();
// here comes processing the coordinates
}
}
});
But I've got coordinates only from network. There's no GPS icon on Android device, pointing that I'm using GPS. Also it doesn't work when I turn off internet connection. How can I enable GPS positioning? In Manifest file GPS is enabled.
I just got bit by this too.
It turns out there's a bug in Sencha: in Ext.util.Geolocation.parseOption they name the parameter allowHighAccuracy but the w3c specs name it enableHighAccuracy.
I added the following code to my application init to fix that:
var parseOptions = function() {
var timeout = this.getTimeout(),
ret = {
maximumAge: this.getMaximumAge(),
// Originally spells *allowHighAccurancy*
enableHighAccuracy: this.getAllowHighAccuracy()
};
//Google doesn't like Infinity
if (timeout !== Infinity) {
ret.timeout = timeout;
}
return ret;
};
Ext.util.Geolocation.override('parseOptions', parseOptions);
For the record: the bug has been reported over a year ago, and the fix was applied for TOUCH-2804 in a recent build. I don't know what that means, but sure enough the bug is still in 2.0
EDIT: using the approach mentioned above doesn't work well either. The GPS icon would turn on and off as Exts calls getCurrentPosition repeatedly using a setInterval. The reason for doing this is that The native watchPosition method is currently broken in iOS5. In my Android targeted application I ended up ditching Ext:util.Geolocation and directely used navigator.geolocation.watchPosition. After that it worked like a charm.
GPS location provider determines location using satellites. Depending on conditions, this provider may take a while to return a location fix.
Requires the permission android.permission.ACCESS_FINE_LOCATION.
Hey I think you need updated longitude and latitude values .
follow this link.. Click Here
I already tried it and test it in android mobile phone.. Its working.
Note : Must and should test in android mobile phone with on GPS status. It will not show on eclipse emulator. But it will show in mobile phone try it..
have a nice.

Categories

Resources