In GPS based applications, it is important that the user enable his GPS. If not then usually we would show a dialog stating that the user "should enable his GPS from the settings to be able to use this functionality".
When the user press OK he will be redirected to the Settings page, I don't like this solution since it takes the user out of the application context in to the settings.
I have noticed that "google maps" application has a better solution, which is to show a neat dialog when a GPS feature is needed. Upon the user's selection "OK" GPS will be enabled directly without any redirection to the settings.
Can I enable the GPS without redirecting the user to the settings screen like in "google maps" app?
checkout the image below:
To have that feature you need:
First (at least) the version 7.0 of play services
compile 'com.google.android.gms:play-services-location:16.0.0'
Second something like this in your code (I had it in my onCreate):
-
// Check the location settings of the user and create the callback to react to the different possibilities
LocationSettingsRequest.Builder locationSettingsRequestBuilder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
PendingResult<LocationSettingsResult> result =
LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, locationSettingsRequestBuilder.build());
result.setResultCallback(mResultCallbackFromSettings);
And then create the callback:
// The callback for the management of the user settings regarding location
private ResultCallback<LocationSettingsResult> mResultCallbackFromSettings = new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
//final LocationSettingsStates locationSettingsStates = result.getLocationSettingsStates();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
// All location settings are satisfied. The client can initialize location
// requests here.
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// Location settings are not satisfied. But could be fixed by showing the user
// a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
status.startResolutionForResult(
MapActivity.this,
REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e) {
// Ignore the error.
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
Log.e(TAG, "Settings change unavailable. We have no way to fix the settings so we won't show the dialog.");
break;
}
}
};
And then, finally, in onActivityResult I had the following:
/**
* Used to check the result of the check of the user location settings
*
* #param requestCode code of the request made
* #param resultCode code of the result of that request
* #param intent intent with further information
*/
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
//final LocationSettingsStates states = LocationSettingsStates.fromIntent(intent);
switch (requestCode) {
case REQUEST_CHECK_SETTINGS:
switch (resultCode) {
case Activity.RESULT_OK:
// All required changes were successfully made
if (mGoogleApiClient.isConnected() && userMarker == null) {
startLocationUpdates();
}
break;
case Activity.RESULT_CANCELED:
// The user was asked to change settings, but chose not to
break;
default:
break;
}
break;
}
}
Related
I have used LocationServices.getSettingsClient() to remove depricated
LocationServices.SettingsApi.checkLocationSettings().
It is asking user to enable location
first time when mainActivity launch if location is disabled.
If in between i disable location . it is not asking to enable location. means
result.addOnSuccessListener is called even if my location is disabled.
if Location is disabled inbetweeen it should ask result.addOnFailureListener
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(getContext());
mSettingsClient = LocationServices.getSettingsClient(getContext());
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
mLocationSettingsRequest = builder.build();
mLocationService = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Task<LocationSettingsResponse> result =
LocationServices.getSettingsClient(getContext()).checkLocationSettings(builder.build());
result.addOnSuccessListener(getActivity(), new OnSuccessListener<LocationSettingsResponse>() {
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
LocationSettingsResponse response =
task.getResult(ApiException.class);
LocationSettingsStates locationSettingsStates = response.getLocationSettingsStates();
if (!locationSettingsStates.isGpsPresent() || !locationSettingsStates.isGpsUsable()) {
//check point 4
}
});
result.addOnFailureListener(getActivity(), new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
if (e instanceof ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
ResolvableApiException resolvable = (ResolvableApiException) e;
resolvable.startResolutionForResult(getActivity(),
REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sendEx) {
// Ignore the error.
}
}
}
});
here I want need to open location enabling dialog using following code:
final Status status = result.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
Log.i(TAG, "All location settings are satisfied.");
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
Log.i(TAG, "Location settings are not satisfied. Show the user a dialog to upgrade location settings ");
try {
// Show the dialog by calling startResolutionForResult(), and check the result
// in onActivityResult().
status.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e) {
Log.i(TAG, "PendingIntent unable to execute request.");
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
Log.i(TAG, "Location settings are inadequate, and cannot be fixed here. Dialog not created.");
break;
}
5 .but using SettingsClient onSucess gives
Task<LocationSettingsResponse> result which does not give statusCode that I recieve in catch block
Update
First Tag is try part of OnComplete() when location is by default on
second time I turn off location and go to other Fragment and again came to main fragment.
Tt executed try part even I location was disabled
I am trying to implement Android In App Update API using AppUpdateManager. I first tried following the documentation, which if you are here, then you know that doesn't work.
So then I've read about a dozen tutorials and blog articles on how to get this to work. I'm about 90% there. For me after the user accepts the update, the update is downloaded, my listener detects that the download is complete, and I display my own message with a call back (most of the tutorials use a Toast at this point, but that shouldn't matter). If my user taps on "Restart" which is the label I gave the OK side of the message that I'm displaying, then I call appUpdateManager.completeUpdate().
At this point I get a screen from Google Play being displayed with some nice animation, and an Installing progress bar when that finishes, the Google screen disappears, and then my app is restarted.
Problem, is that it didn't get installed, I can tell from my app version that it is still the previous version, and since it is still the previous version, the appUpdateManager is recreated and when it checks UpdateAvailability.UPDATE_AVAILABLE, it finds (obviously) that there is an update available, and goes back through the whole processing, downloading it again and trying to restart the app again.
I have added some log messages and checked to see if I am getting RESULT_IN_APP_UPDATE_FAILED in the onActivityResult, but it is coming back fine.
Any help or suggestions anyone has, would be great.
I create a handle to appUpdateManager at the beginning of MainActivity, like this:
private AppUpdateManager appUpdateManager;
I also create a listener to monitor the install state as I am working towards a FLEXABLE AppUpdateType like:
private InstallStateUpdatedListener UPDATE_LISTENER = installState -> {
if (installState.installStatus() == DOWNLOADED) {
Log.d(TAG, "~UPDATE_LISTENER - installStatus is DOWNLOADED");
Utility.displayAlert(UPDATE_READY);
}
Log.d(TAG, "~Error code is: " + installState.installErrorCode());
Log.d(TAG, "~Package name is: " + installState.packageName());
};
In my onCreate, I create the appUpdateManager and register the download listener as well as add the addOnSuccessListener like so:
Log.d(TAG, "~updateAppIfAvailable");
// Creates instance of the manager.
appUpdateManager = AppUpdateManagerFactory.create(this);
Log.d(TAG, "~registerListener");
appUpdateManager.registerListener(UPDATE_LISTENER);
appUpdateManager
.getAppUpdateInfo()
.addOnSuccessListener(
appUpdateInfo -> {
// Checks that the platform will allow the specified type of update.
Log.d(TAG, "~updateAvailability is " + appUpdateInfo.updateAvailability());
if ((appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE)
&& appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
// Request the update.
try {
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
AppUpdateType.FLEXIBLE,
this,
MY_REQUEST_CODE);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
});
My onActivityResult looks like this:
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "~onActivityResult");
if (requestCode == MY_REQUEST_CODE) {
switch (resultCode) {
case Activity.RESULT_OK:
Log.d(TAG, "~User approved update");
break;
case Activity.RESULT_CANCELED:
Log.d(TAG, "~User rejected update");
break;
case RESULT_IN_APP_UPDATE_FAILED:
Log.d(TAG, "~Update failed");
break;
}
}
}
onResume is:
appUpdateManager
.getAppUpdateInfo()
.addOnSuccessListener(
appUpdateInfo -> {
if (appUpdateInfo.updateAvailability()
== UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
// If an in-app update is already running, resume the update.
try {
Log.d(TAG, "~onResume appUpdateManager is calling startUpdateFlowForResult");
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
AppUpdateType.FLEXIBLE,
this,
MY_REQUEST_CODE);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
});
Finally when I display my alert (this could be a Toast if you wanted), I have both a Cancel and a Restart option with a message that says "Update download is complete."
If the user presses the "Restart" option, then it calls this updateAndRestart() method:
private void updateAndRestart() {
Log.d(TAG, "~updateAndRestart");
Log.d(TAG, "~Completing app update.");
if (appUpdateManager != null) {
appUpdateManager.completeUpdate();
Log.d(TAG, "~unregisterListener");
appUpdateManager.unregisterListener(UPDATE_LISTENER);
}
}
Ok, it's been a week, apparently I've stumped the entire SO community. :) Seriously though, I've been reading Android docs and tutorials for the past week and I have no other answers, so I'm going to just say the Google Update API just isn't ready for production.
I found an alternate solution. It is a combination of
Using the AppUpdater library as mentioned in the answer to this question.
If I get a callback that the user tapped Update, then I take them to my Play Store App listing, using this intent. Make sure you replace "com.example.android" with your own app id. This google doc page shows you how to do it.
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://play.google.com/store/apps/details?id=com.example.android"));
intent.setPackage("com.android.vending");
startActivity(intent);
I have a web view android app that using google map current location to get user location, when user click on an icon I am calling a native function to access the gps, the issue is when open the app with offline GPS, then click on icon it will ask to on the gps and when press ok nothing will happen, even click on the icon again still nothing will happen unless close the app and open again then it will work, please help it really made me get crazy...
public void location_request()
{
final LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(30 * 1000);
locationRequest.setFastestInterval(5 * 1000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
builder.setAlwaysShow(true);
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(MainActivity.this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
mGoogleApiClient.connect();
PendingResult<LocationSettingsResult> result =
LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
final LocationSettingsStates state = result.getLocationSettingsStates();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
//The client can initialize location
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// Location settings are not satisfied.
try {
status.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e) {
// Ignore the error.
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
break;
}
}
});
}
Use this code to enable GPS and make sure location permission is given. Initially when GPS is disabled then onFailureListener will trigger and popup GPS enable dialog but after pressing ok it will not trigger onSuccessListener so you need to make current location request from onActivityResult but if GPS is enabled before entering the app then onSuccessListener will trigger and u can request for current location from there.
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10000);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
SettingsClient client = LocationServices.getSettingsClient(HomeActivity.this);
Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());
task.addOnSuccessListener(HomeActivity.this, locationSettingsResponse -> {
// Make your current location request here
});
task.addOnFailureListener(HomeActivity.this, e -> {
if (e instanceof ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
ResolvableApiException resolvable = (ResolvableApiException) e;
resolvable.startResolutionForResult(HomeActivity.this,
REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sendEx) {
// Ignore the error.
}
}
});
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == REQUEST_CHECK_SETTINGS) {
// Make your current location request here
}
}
Reference: https://developer.android.com/training/location/change-location-settings
I have a class used as interface inside my MainActivity.java:
public class prova{
prova(){
}
#JavascriptInterface
public void displayGPSRequest() {
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
Log.i(TAG, "All location settings are satisfied.");
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
Log.i(TAG, "Location settings are not satisfied. Show the user a dialog to upgrade location settings ");
try {
// Show the dialog by calling startResolutionForResult(), and check the result
// in onActivityResult().
status.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e) {
Log.i(TAG, "PendingIntent unable to execute request.");
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
Log.i(TAG, "Location settings are inadequate, and cannot be fixed here. Dialog not created.");
break;
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
//final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);
switch (requestCode)
{
case REQUEST_CHECK_SETTINGS:
switch (resultCode)
{
case Activity.RESULT_OK:
{
// All required changes were successfully made
Toast.makeText(MainActivity.this, "Location enabled by user!", Toast.LENGTH_LONG).show();
break;
}
case Activity.RESULT_CANCELED:
{
// The user was asked to change settings, but chose not to
Toast.makeText(MainActivity.this, "Location not enabled, user cancelled.", Toast.LENGTH_LONG).show();
break;
}
default:
{
break;
}
}
break;
}
}
});
}
}
Inside the function displayGPSRequest() I have startResolutionForResult() that should call the method onActivityResult() but it never does. I tried to see other posts where they used fragments but I don't have really understood them. I hope you can help with this.
onActivityResult should be overriden in the associated Activity - currently you're just declaring a method in the ResultCallback which never gets called.
I would like to update user's location every few minutes in background.I used this sample code googlesamples/android-play-location
but changing it to use with Service
public class MyService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener, ResultCallback<LocationSettingsResult>
but I can't check location settings
protected void checkLocationSettings() {
PendingResult<LocationSettingsResult> result =
LocationServices.SettingsApi.checkLocationSettings(
mGoogleApiClient,
mLocationSettingsRequest
);
result.setResultCallback(this);
}
#Override
public void onResult(LocationSettingsResult locationSettingsResult) {
final Status status = locationSettingsResult.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
Log.i(TAG, "All location settings are satisfied.");
startLocationUpdates();
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
Log.i(TAG, "Location settings are not satisfied. Show the user a dialog to" +
"upgrade location settings ");
try {
// Show the dialog by calling startResolutionForResult(), and check the result
// in onActivityResult().
status.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e) {
Log.i(TAG, "PendingIntent unable to execute request.");
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
Log.i(TAG, "Location settings are inadequate, and cannot be fixed here. Dialog " +
"not created.");
break;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
// Check for the integer request code originally supplied to startResolutionForResult().
case REQUEST_CHECK_SETTINGS:
switch (resultCode) {
case Activity.RESULT_OK:
Log.i(TAG, "User agreed to make required location settings changes.");
startLocationUpdates();
break;
case Activity.RESULT_CANCELED:
Log.i(TAG, "User chose not to make required location settings changes.");
break;
}
break;
}
}
Because this method requires an Activity
status.startResolutionForResult(MainActivity.this,
REQUEST_CHECK_SETTINGS);
and if I put the previous code in the MainActvity, I would not have the references to mGoogleApiClient and mLocationSettingsRequest
LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient,
mLocationSettingsRequest);
I would like to upgrade and save in background the position even if the activity is destroyed.
Use the service is the correct way to do this?
And how do I check the location settings?
[EDIT]
I tried to use the PendingIntent and an IntentService
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, mPendingIntent);
This method is suited for the background use cases, more specifically
for receiving location updates, even when the app has been killed by
the system.
What is the difference compared to the version with the Service and LocationListner?
I found a solution for my problem.
To access the Main Activity I used the method
MainActivity.getInstance()
MainActivity
public class MainActivity extends AppCompatActivity {
private static MainActivity instance;
public static MainActivity getInstance() {
Log.i("MainActivity", "getInstance");
return instance;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Instance of the MainActivity
instance = this;
}
...
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.i(TAG, "onActivityResult");
switch (requestCode) {
// Check for the integer request code originally supplied to startResolutionForResult().
case REQUEST_CHECK_SETTINGS:
switch (resultCode) {
case Activity.RESULT_OK:
Log.i(TAG, "User agreed to make required location settings changes.");
startService(intent);
break;
case Activity.RESULT_CANCELED:
Log.i(TAG, "User chose not to make required location settings changes.");
break;
}
break;
}
}
}
Service
#Override
public void onResult(LocationSettingsResult locationSettingsResult) {
final Status status = locationSettingsResult.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
// All location settings are satisfied. The client can
// initialize location requests here.
Log.i(TAG, "All location settings are satisfied.");
startLocationUpdates();
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
Log.i(TAG, "Location settings are not satisfied. Show the user a dialog to " +
"upgrade location settings ");
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
status.startResolutionForResult(MainActivity.getInstance(), REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e) {
// Ignore the error.
Log.i(TAG, "PendingIntent unable to execute request.");
}
break;
// The status will never be SETTINGS_CHANGE_UNAVAILABLE if use builder.setAlwaysShow(true);
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location settings are not satisfied. However, we have no way
// to fix the settings so we won't show the dialog.
Log.i(TAG, "Location settings are inadequate, and cannot be fixed here. Dialog " +
"not created.");
break;
}
}