I'm using the Google API (Fuse Location Provider) to track a device's location but I need to prevent the user from disabling the GPS. I read a lot of answers but all I've found is: No, can't do, rooting the device or bug exploits. A friend just showed me a parental control app that accomplishes this without having to root the device. About user privacy, etc. The code will be used only in company's devices with the users being aware of this.
At least I need a way to detect if the GPS has been deactivated to notify the user, by the way I can't find any reference to this in the Google API.
Thanks a lot in advance.
GpsStatus.Listener - Try reading this.
You can override the method onGpsStatusChanged:
#Override
abstract void onGpsStatusChanged(int event){
if (event==GPS_EVENT_STOPPED){
LocationManager mlocManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
boolean enabled = mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if(!enabled){
//toggle your notification
}
}
}
Related
So, I'm trying to build a weather app for practice and I've been running into the problem of trying to get the location. I've read people suggest to use getLastLocation through the fused location API, problem with that is if they don't already have a location registered on the device it comes up null. I've noticed using the emulator times that this come up is rare, but I'd still like my app to handle it properly. One instance where you might run into this is if they just turned GPS off and back on, or if the phone was just turned on. One thing I did was if getLastLocation does come back null, is to request an update, but then you still have to wait for the device to register an updated location, which with a weather app all of the data is based off of and you're still kind of running into the same problem. I've noticed with other apps this isn't a problem, like sometimes I actually have to load up Google Maps to get it to register a location. How does Google Maps force it to update the location? Here's the example from my getLocation method:
public void getLocation() throws SecurityException {
boolean gps_enabled;
LocationManager lm = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (gps_enabled) {
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (location != null) {
startGetForecast(location);
} else {
LocationRequest request = LocationRequest.create();
request.setNumUpdates(1);
request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, request, this);
}
}
else {
AlertDialogFragment alertDialogFragment = new AlertDialogFragment();
alertDialogFragment.setErrorTexts("Location Unavailable", "Could not retrieve location information.", "Exit");
alertDialogFragment.show(getSupportFragmentManager(), "Location Unavailable");
}
}
Note: This answer could sound like not answering to the question directly but after chatting (comments in question) with OP as his code was ok in general but the condition around the problem, this answer has satisfied OP.
Fortunately, the standard library Is not the only way Google can get
code into your hands. In addition to the standard library, Google
provider Play services. This is a set of common services that are
installed alongside the Google Play store application. To fix this
location mess, Google shipped a new locations services in Play
Services called the Fused Location Provider.
Since these libraries
live in another application, you must actually have that application
installed. This means that only devices with the Play Store app
installed and up to date will be able to use your application.
So the conclusion is:
You need to test the app on your device as mentioned above.
Since you are using Fused Location Provider Api, that means the Api will automatically determine last location from one of the following sources:
GPS radio
Coarse points from cell towers
WiFi connections
So you could easily remove the GPS if condition from your code
Be a ware of that if you must use GPS signal, you need to be out side the building, lab, home or office.
If you want to dig more find more in the mentioned resources and there is a lot of online resources.
Resources: The first part of the answer, the source of it is from:
Android Programming: The Big Nerd Ranch Guide 2nd edition chapter 31 page 552 under Google Play Services
I'm working with geofences on android, it's all working fine on most phones,
but on some of them, it's just not working (showing "geofences not available" in my error logs).
Some users don't have their location tracking enabled for Google Play Services.
I think that is the reason why geofencing is not working on their phones. (right?)
Now I want a way to detect this. (inform the user and eventually show them how to fix it)
I know there is a way to know wether google play services is available or not (and I already do this), but that doesn't say anything about the location services being enabled or not.
I know that I can check it while adding or removing geofence, there is an error code for it (geofence not available Location Status Codes), but that's not enough.
Some users disable the location services after they added the geofences. Then I have no way of knowing this, and my app won't work. (complaining users etc.).
At least I have to inform the user when they open the app to check what's wrong.
Does someone have an idea on how to do this?
The best I can do now is adding and removing a dummy geofence on app boot, but there has to be a better way?
EDIT:
I tested it with a device that had the issue, removing the app and reinstalling seems to fix the problem.
I'm not doing anything special on the first boot, so this is really weird.
It looks as if there is a problem with the google play services connection, and reinstalling the app does something special with these services.
Is this possible? It gives no errors while connecting to them, but it did when I tried to set geofences (see above).
The geofences will get disabled (and unregistered) if the GPS Provider or the Network Provider are disabled for whatever reason. That will cause your onAddGeofencesResult() to get called with an status code of error (1000). You can detect it right there.
Or, you detect this by implementing a Receiver that gets called in response to android.location.PROVIDERS_CHANGED. Remember to add the receiver to the AndroidManifest
<receiver android:name=".service.GeofenceProvidersChangedBroadcastReceiver">
<intent-filter>
<action android:name="android.location.PROVIDERS_CHANGED"/>
</intent-filter>
</receiver>
On the receiver implementation, on its onReceive(), get the location manager and test for the providers status:
public class ProvidersChangedBroadcastReceiver extends WakefulBroadcastReceiver {
:
:
#Override
public void onReceive(Context context, Intent intent) {
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
// GPS_PROVIDER IS enabled...
} else {
// GPS_PROVIDER is NOT enabled...
}
if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
// NETWORK_PROVIDER IS enabled...
} else {
// NETWORK_PROVIDER is NOT enabled...
}
:
:
:
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) &&
locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
// We are good for geofencing as both GPS and Network providers are enabled....
}
:
:
:
}
It seems that from Android OS version 4.1 there is a new setting, wich allows google applications use the user location.
I am developping a app that use the google maps api v2, and I made it location aware by using the following line:
mMap.setMyLocationEnabled(true);
Now i want to check if the user has checked the location & google search at the settings screen.
There is no problem reading if the wifi and the gps is enabled, but i can not find the way to check of the google location & search is enabled until now i have just found the following piece of code:
try {
int gEnable= settings.System.getInt(getActivity().getContentResolver(),Settings.ACTION_SEARCH_SETTINGS);
} catch (SettingNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
But it always throws the exception.
Thank you very much for reading my post.
EDIT
I will try to explain it more clear....
In my app I Just want to check programmaticaly if the "Location and google search" (as i show in the picture below) is checked.
Thank u very much for reading my question.
I don't completely understand your question, though considering to do something like this might be also a way.
boolean enabled = locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
// Check if GPS is enabled, if not send user to GPS settings
if (!enabled) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivityForResult(intent, 0);
}
besides LocationManager.GPS_PROVIDER you could also ask for
LocationManager.PASSIVE_PROVIDER, which is "a special location provider for receiving locations without actually initiating a location fix" or
LocationManager.NETWORK_PROVIDER, which uses the network location. Google doesn't do anything else than using the last two options in my opinion...
I hope that helps...
One user of my app reported that app tells network for location is off even he did turn it on. He sent me few screen shots and they made me think;
LocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
is not working properly. His phone is running Android 4.1.2 and first I thought this is the cause of this issue. But it was not the case. He sent me a screen shot of that setting too.
Then I googled and found this. The question seems to help me but unfortunately answer was not helpful for this case and questioner did not pursue farther.
My app is related to location and have been using LocationManager.isProviderEnabled to know GPS and Network for location is on or off. I have never been told my app is not properly knowing those settings until recently. He is the first user who reported the issue. I learned there are another method to know GPS and Network for location settings, by seeing Secure.LOCATION_PROVIDERS_ALLOWED. To see how this method work on his phone, I wrote simple app and asked him to run. This app does simple task and shows text on screen.
LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
{
string = "GPS=on\n";
}
else
{
string = "GPS=off\n";
}
if(locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
{
string += "Network=on\n";
}
else
{
string += "Network=off\n";
}
String status = android.provider.Settings.Secure.getString(getContentResolver(), Secure.LOCATION_PROVIDERS_ALLOWED);
if(status.contains("gps"))
{
string += "GPS=on\n";
}
else
{
string += "GPS=off\n";
}
if(status.contains("network"))
{
string += "Network=on\n";
}
else
{
string += "Network=off\n";
}
He sent back screen shot again. It looks;
GPS=on
Network=off
GPS=on
Network=on
This result did not make me happy. There could be some possibilities for this.
As other person questioned before, this issue has been there on some phones.
Google broke this with 4.1.2. isProviderEnabled does not work on this version.
Although not documented, starting 4.1.2, isProviderEnabled won't work as it did before.
No, Google changed anything. This is a bug for this particular phone.
Now my questions are;
Is LocationManager.isProviderEnabled still valid for Android 4.1.2 and later?
Does seeing Secure.LOCATION_PROVIDERS_ALLOWED have some drawbacks/pit holes (when I gave up using LocationManager.isProviderEnabled?
Thanks in advance.
EDIT1:
Here you can download test app from Google Play to try or ask someone to try.
EDIT6:
I removed test app since this question is answered.
EDIT2:
I released my app which checks network provider is usable by seeing Secure.LOCATION_PROVIDERS_ALLOWED and got exception on limited phones.
These are ACRA's report.
Some phone running OS 4.1.1.
java.lang.IllegalArgumentException: requested provider network doesn't exisit
at android.os.Parcel.readException(Parcel.java:1434)
at android.os.Parcel.readException(Parcel.java:1384)
at android.location.ILocationManager$Stub$Proxy.requestLocationUpdates(ILocationManager.java:675)
at android.location.LocationManager._requestLocationUpdates(LocationManager.java:686)
at android.location.LocationManager.requestLocationUpdates(LocationManager.java:508)
Some phone running OS 4.1.2.
java.lang.IllegalArgumentException: provider=network
at android.os.Parcel.readException(Parcel.java:1439)
at android.os.Parcel.readException(Parcel.java:1389)
at android.location.ILocationManager$Stub$Proxy.requestLocationUpdates(ILocationManager.java:659)
at android.location.LocationManager._requestLocationUpdates(LocationManager.java:690)
at android.location.LocationManager.requestLocationUpdates(LocationManager.java:512)
I have never seen those exceptions until I changed a method to check network provider for location is usable or not. So I think LocationManager.isProviderEnabled is safe and seeing Secure.LOCATION_PROVIDERS_ALLOWED is risky. But this will put me back to original issue. Why LocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) returns false (and there is not really) when Secure.LOCATION_PROVIDERS_ALLOWED tells there IS. Is Android OS poorly designed? Or I have just seeing issues tied only to specific (but there are at least 2 of them) phones?
EDIT3:
I updated test app to show GPS/Network location provider seems really usable or not by accessing with requestLocationUpdates().
And I disclose 2 phones name.
1) SBM200SH, OS4.1.2, Softbank mobile, Sharp Corporation
2) HTX21 (INFOBAR A02), OS4.1.1, KDDI, HTC
EDIT4:
I found 3rd phone.
3) SBM203SH, OS4.1.2, Softbank mobile, Sharp Corporation
EDIT5:
Sharp Corporation is running discussion space for mobile developers. I posted topic by presenting this SO's question. I hope someone at Sharp Corporation takes action for this. I will keep this updated.
Developer support provided by Sharp corporation is excellent and they answered to my question in less than 48 hours.
This is what I got from them.
There are 2 conditions must be met that LocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) returns true.
Some internal state is ready for network location.
Network location is enabled on setting screen.
Second one is obvious. But first one is not. They told how to simulate first one is negative. You can confirm the issue with steps shown below and running my test app (please see my question for link to download).
Open settings of you phone.
Tap Applications.
Tap All tab.
Find "Network Location", tap it.
Tap "Disable".
Reboot your phone.
Run test app.
For reason I can't understand the user's phone failed to do something related to first condition shown above and exhibits the issue.
Conclusion:
LocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) is reliable. And be aware, Secure.LOCATION_PROVIDERS_ALLOWED is less reliable.
The modern way to check the users Location settings is through LOCATION_MODE in Settings.Secure
For example if you simply want to know if the user has disabled them or not, you can do:
public static boolean isLocationEnabled(Context context) {
return getLocationMode(context) != Settings.Secure.LOCATION_MODE_OFF;
}
private static int getLocationMode(Context context) {
return Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
}
This will return true if Location is enabled. If you need finer granularity see the docs for details.
This method is better suited when using the Google Services Location APIs than the old NETWORK_PROVIDER and GPS_PROVIDER ways. Note: Requires KitKat / API19
Not directly an answer to your question(s), but check out the new Location API that Google launched last week. It's really easy to implement and it will check for the best possible location without wasting battery.
http://developer.android.com/google/play-services/location.html
and here's a session at Google I/O about this new API and how to use it.
http://www.youtube.com/watch?v=Bte_GHuxUGc
This way you don't need to worry about checking if the GPS is on or not and stuff like that
Location Manager is not reliable on some phones. You may notice that if you launch google maps all of a sudden your app works. That is because Google Maps kicked the LocationManager. Which also means that there is programmatic way to kick that dude alive. So I used
HomeScreen.getLocationManager().requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 0, 0, new LocationListener() {
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onLocationChanged(final Location location) {
}
});
After the above code, I called what ever I needed from LocationManager and it kinda worked. If not try out the new API's LocationClient. This is suppose to be much better, battery, accuracy and reliability.
I'd like to know if it possible to enable and disable Location Services programatically in Android 4.0?
I've found several approaches how to do this for previous versions of Android (for instance, this is the most popular link). But these approach does not work for Android ICS.
Also, I understand that an application should not do this but, for instance, default widget does this.
Can anybody clarify if it is possible and how to achieve this?
In a tiny app I have developed, I turn off the gps by just disabling the location on the MyLocationOverlay. Of course, this will work only if you are using maps from Google as that class belongs to the Google API's.
myLocationOverlay.disableMyLocation();
I place the line on the onStop() method and only if it is currently enabled. And every time my app goes to the background, the GPS turns automatically off.
Hope it helps.
You can enable and disable gps device but users must confirm in setting widget.
The solution in this topic.
LocationManager L = (LocationManager) getSystemService(LOCATION_SERVICE);
if (!L.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Intent I = new Intent(
android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(I);
}