From the Flutter side, using the PlatformChannel, I am navigating to an Android Java activity, and doing some processes.
The activity successfully opens and I'm able to do the functionality and have the final result of it.
How may I navigate back to the Flutter side to a specific page and pass a value?
P.S.: without going back to the same page and then redirecting to the
next page.
On the Flutter side:
I have these variables
/// Filters Method Channel
final filtersChannel = const MethodChannel('flutter.native/filters');
/// Filters Method Channel
final filtersResultChannel = const MethodChannel("flutter.native/result_filters");
I have a floatingActionButton with this function which invokes a MethodChannel
Future<void> startNewActivity() async {
try {
await filtersChannel.invokeMethod('open_filters');
} on PlatformException catch (e) {
debugPrint("Failed to Invoke: '${e.message}'.");
}
}
On the MainActivity.java
On the protected void onCreate(#Nullable Bundle savedInstanceState) function, I'm starting an activity which has the AR video recording like this:
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this, FiltersActivity.class);
startActivity(intent);
}
On the FiltersActivity.java
On the public void configureFlutterEngine(#NonNull FlutterEngine flutterEngine) function
I’m defining and invoking my two channels:
The flutter.native/result_filters channel which builds the UI and
the functionality.
The flutter.native/filters channel which returns the final result.
Here:
#Override
public void configureFlutterEngine(#NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
String resultFiltersChannelIdentifier = "flutter.native/result_filters";
filtersResultChannel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), resultFiltersChannelIdentifier);
String filtersChannelIdentifier = "flutter.native/filters";
MethodChannel filtersChannel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), filtersChannelIdentifier);
filtersChannel.setMethodCallHandler(this::filtersMethodCallHandler);
}
Then, the flutter.native/filters displays the UI using the filtersMethodCallHandler function. Here:
private void filtersMethodCallHandler(MethodCall methodCall, MethodChannel.Result result) {
if (methodCall.method.equals("open_filters")) {
openUI();
} else {
result.notImplemented();
}
}
In the openUI function, I'm assigning the record button a function, here:
recordButton.setOnClickListener(this::toggleRecording);
And here's the toggleRecording function:
public void toggleRecording(View unusedView) {
boolean recording = videoRecorder.onToggleRecord();
if (recording) {
recordButton.setImageResource(R.drawable.round_stop);
Toast.makeText(this, "Started Recording", Toast.LENGTH_SHORT).show();
} else {
recordButton.setImageResource(R.drawable.round_videocam);
Toast.makeText(this, "Recording Stopped", Toast.LENGTH_SHORT).show();
videoPath = videoRecorder.getVideoPath().getAbsolutePath();
Toast.makeText(this, "Video saved: " + videoPath, Toast.LENGTH_SHORT).show();
Log.d(TAG, "Video saved: " + videoPath);
// Send notification of updated content.
ContentValues values = new ContentValues();
values.put(MediaStore.Video.Media.TITLE, "Sceneform Video");
values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
values.put(MediaStore.Video.Media.DATA, videoPath);
getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
filtersResultChannel.invokeMethod("filters_result", videoPath);
finish();
}
}
As shown above, I'm invoking the filters_result method for the filtersResultChannel channel and I'm adding the videoPath to it.
And then, I'm calling the finish(); method to close the FiltersActivity and return back to the MainAvtivity which successfully returns me to the Flutter page!
BACK to the Flutter side,
I'm listening to the filtersResultChannel like this:
#override
void initState() {
super.initState();
filtersResultChannel.setMethodCallHandler(_filtersResultHandler);
}
Future _filtersResultHandler(MethodCall methodCall) async {
if (methodCall.method == "filters_result") {
final videoPath = methodCall.arguments;
if (videoPath != null && videoPath.length >= 0) {
SchedulerBinding.instance.addPostFrameCallback((_) {
debugPrint("YES YES YES => $videoPath");
setState(() {
reportStatus = videoPath;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => VideoShow(clipPath: videoPath),
),
);
});
});
}
return null;
} else {
return null;
}
}
As shown above, I have a debugPrint statement, this statement prints the returned videoPath from the filtersResultChannel
<--------->
THE PROBLEM
<--------->
Even though I'm successfully getting the videoPath value and successfully returning back to the Flutter page, I'm NOT able to use it!!
The setState(); doesn't update the UI NOR navigate to the next screen, the VideoShow screen!
HOW MAY I FIX SUCH AN ISSUE?
Following this guide https://developers.google.com/admob/ump/android/quick-start I tried to add everything to my app.
What I did:
link funding choices to admob
added ump to build.gradle
added the app ID to android manifest
set up a dialog for the app in admob and activated it for the app
Then I added this code to my app
ConsentRequestParameters params = new ConsentRequestParameters
.Builder()
.setTagForUnderAgeOfConsent(false)
.build();
consentInformation = UserMessagingPlatform.getConsentInformation(this);
consentInformation.requestConsentInfoUpdate(
this,
params,
new ConsentInformation.OnConsentInfoUpdateSuccessListener() {
#Override
public void onConsentInfoUpdateSuccess() {
// The consent information state was updated.
// You are now ready to check if a form is available.
if (consentInformation.isConsentFormAvailable()) {
loadForm();
}
else {
Context context = getApplicationContext();
CharSequence toastText = "No Form Available";
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, toastText, duration);
toast.show();
}
}
},
new ConsentInformation.OnConsentInfoUpdateFailureListener() {
#Override
public void onConsentInfoUpdateFailure(FormError formError) {
// Handle the error.
Context context = getApplicationContext();
CharSequence toastText = "Error";
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, toastText, duration);
toast.show();
}
});
and
public void loadForm() {
UserMessagingPlatform.loadConsentForm(
this,
new UserMessagingPlatform.OnConsentFormLoadSuccessListener() {
#Override
public void onConsentFormLoadSuccess(ConsentForm consentForm) {
MainActivity.this.consentForm = consentForm;
if(consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.REQUIRED) {
consentForm.show(
MainActivity.this,
new ConsentForm.OnConsentFormDismissedListener() {
#Override
public void onConsentFormDismissed(#Nullable FormError formError) {
// Handle dismissal by reloading form.
loadForm();
}
});
}
}
},
new UserMessagingPlatform.OnConsentFormLoadFailureListener() {
#Override
public void onConsentFormLoadFailure(FormError formError) {
// Handle the error
}
}
);
}
However, I always end up getting the toast "Error" landing in onConsentInfoUpdateFailure(FormError formError) independet from testing on my mobile phone or in the virtual device (I am in europe btw).
Am I missing something?
Thanks,
Celdri
I had the same issue and I solved it just by configuring properly my adMob account.
I am implementing Camera X. The issue i am facing is to implement a mechanism to lock/freeze camera preview when picture is captured. Currently i have implement a workaround but it doesn't work well if the flash light is on while capturing. I get a frame from previewView (PreviewView) previewView.getBitmap() as before capturing the image and then display in an captureImage (ImageView). But the the freeze frame not show flash light update. My current code is below
private void capturePhoto() {
showProgress(true);
// Get the Information to be used & stored with Image
ContentValues contentValues = getImageSaveInfo();
Uri externalUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ImageCapture.OutputFileOptions options = new ImageCapture.OutputFileOptions
.Builder(getContentResolver(), externalUri, contentValues)
.build();
// Play the Capture Sound when a picture is captured.
playCameraShutterSound();
// Display current frame From Preview in ImageView.
freezePreview(true);
imageCapture.takePicture(options,
ContextCompat.getMainExecutor(this),
new ImageCapture.OnImageSavedCallback() {
#Override
public void onImageSaved(#NonNull ImageCapture.OutputFileResults results) {
ToastUtility.successToast(getApplicationContext(),
"Photo Capture Successfully");
// Update Last Taken Image View with new Image
getLastTakenImage();
if (results.getSavedUri() != null) {
Log.d(TAG, "Image Saved At -> " + results.getSavedUri().toString());
}
showProgress(false);
freezePreview(false);
}
#Override
public void onError(#NonNull ImageCaptureException exception) {
ToastUtility.errorToast(getApplicationContext(),
"Photo Couldn't Capture");
Log.d(TAG, "Image Capture Error -> " + exception.getMessage());
showProgress(false);
freezePreview(false);
}
});
}
private void freezePreview(boolean value) {
if (value) {
Bitmap bitmap = mainBinding.previewView.getBitmap();
Glide.with(getApplicationContext())
.load(bitmap).into(mainBinding.captureImage);
mainBinding.captureImage.setVisibility(View.VISIBLE);
mainBinding.previewView.setVisibility(View.INVISIBLE);
} else {
mainBinding.previewView.setVisibility(View.VISIBLE);
mainBinding.captureImage.setVisibility(View.INVISIBLE);
}
}
The flash is triggered at some point after takePicture() is called, there isn't a callback for it in CameraX, so there isn't a direct way to know when it's fired.
You can instead use camera2 interop to indirectly check for the flash state. You can add a session CaptureCallback to ImageCapture's config, then inside the callback's onCaptureCompleted, check if the flash state of the total result is FIRED.
// Override onCaptureCompleted to check for the flash state
CameraCaptureSession.CaptureCallback sessionCaptureCallback = //... ;
// Initialize an ImageCapture builder
ImageCapture.Builder configBuilder = new ImageCapture.Builder();
// Add the session CaptureCallback to it
new Camera2Interop.Extender<>(configBuilder)
.setSessionCaptureCallback(sessionCaptureCallback);
// Build the ImageCapture use case
ImageCapture useCase = configBuilder.build();
I know that the question about turning on/off GPS programatically on android has been discussed many times, and the answer is always the same:
"You can't for security/privacy reasons, you have to forward to location preferences screen and let the user enable/disable it."
I understand that, however I recently bought Tasker from the market and, among many other things that you can accomplish with it, you can set rules to auto-enable GPS on entering pre-determined applications and disable it on exit (see here for the tutorial on how to do it, and it just works!) and this app can't be signed with the firmware signing key as it works on many android versions and different devices and you don't even need to be rooted.
I would like to do this in my app. Of course, I don't want to blow up the users privacy, so I would first ask the user if he wants to turn it on automatically with the typical "remember my decision" checkbox and if he answers yes, enable it.
Does anybody have any idea or clue on how Tasker achieves this?
the GPS can be toggled by exploiting a bug in the power manager widget. see this xda thread for discussion.
here's some example code i use
private void turnGPSOn(){
String provider = Settings.Secure.getString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
if(!provider.contains("gps")){ //if gps is disabled
final Intent poke = new Intent();
poke.setClassName("com.android.settings", "com.android.settings.widget.SettingsAppWidgetProvider");
poke.addCategory(Intent.CATEGORY_ALTERNATIVE);
poke.setData(Uri.parse("3"));
sendBroadcast(poke);
}
}
private void turnGPSOff(){
String provider = Settings.Secure.getString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
if(provider.contains("gps")){ //if gps is enabled
final Intent poke = new Intent();
poke.setClassName("com.android.settings", "com.android.settings.widget.SettingsAppWidgetProvider");
poke.addCategory(Intent.CATEGORY_ALTERNATIVE);
poke.setData(Uri.parse("3"));
sendBroadcast(poke);
}
}
use the following to test if the existing version of the power control widget is one which will allow you to toggle the gps.
private boolean canToggleGPS() {
PackageManager pacman = getPackageManager();
PackageInfo pacInfo = null;
try {
pacInfo = pacman.getPackageInfo("com.android.settings", PackageManager.GET_RECEIVERS);
} catch (NameNotFoundException e) {
return false; //package not found
}
if(pacInfo != null){
for(ActivityInfo actInfo : pacInfo.receivers){
//test if recevier is exported. if so, we can toggle GPS.
if(actInfo.name.equals("com.android.settings.widget.SettingsAppWidgetProvider") && actInfo.exported){
return true;
}
}
}
return false; //default
}
All these answers are not allowed now. Here is the correct one:
For all those still looking for the Answer:
Here is how OLA Cabs and other such apps are doing it.
Add this in your onCreate
if (googleApiClient == null) {
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API).addConnectionCallbacks(this)
.addOnConnectionFailedListener(Login.this).build();
googleApiClient.connect();
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); // this is the key ingredient
// **************************
PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi
.checkLocationSettings(googleApiClient, 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:
// 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(Login.this, 1000);
} catch (IntentSender.SendIntentException e) {
// Ignore the error.
}
break;
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.
break;
}
}
});
}
These are the implmented methods:
#Override
public void onConnected(Bundle arg0) {
// TODO Auto-generated method stub
}
#Override
public void onConnectionSuspended(int arg0) {
// TODO Auto-generated method stub
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
// TODO Auto-generated method stub
}
Here is the Android Documentation for the same.
This is to help other guys if they are still struggling:
Edit: Adding Irfan Raza's comment for more help.
#Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1000) {
if(resultCode == Activity.RESULT_OK){
String result=data.getStringExtra("result");
} if (resultCode == Activity.RESULT_CANCELED) {
//Write your code if there's no result
}
}
}
ENABLE GPS:
Intent intent=new Intent("android.location.GPS_ENABLED_CHANGE");
intent.putExtra("enabled", true);
sendBroadcast(intent);
DISABLE GPS:
Intent intent = new Intent("android.location.GPS_ENABLED_CHANGE");
intent.putExtra("enabled", false);
sendBroadcast(intent);
This code works on ROOTED phones if the app is moved to /system/aps, and they have the following permissions in the manifest:
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
Code
private void turnGpsOn (Context context) {
beforeEnable = Settings.Secure.getString (context.getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
String newSet = String.format ("%s,%s",
beforeEnable,
LocationManager.GPS_PROVIDER);
try {
Settings.Secure.putString (context.getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
newSet);
} catch(Exception e) {}
}
private void turnGpsOff (Context context) {
if (null == beforeEnable) {
String str = Settings.Secure.getString (context.getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
if (null == str) {
str = "";
} else {
String[] list = str.split (",");
str = "";
int j = 0;
for (int i = 0; i < list.length; i++) {
if (!list[i].equals (LocationManager.GPS_PROVIDER)) {
if (j > 0) {
str += ",";
}
str += list[i];
j++;
}
}
beforeEnable = str;
}
}
try {
Settings.Secure.putString (context.getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
beforeEnable);
} catch(Exception e) {}
}
Instead of using intent Settings.ACTION_LOCATION_SOURCE_SETTINGS you can directly able to show pop up in your app like Google Map & on Gps on click of ok button their is no need to redirect to setting simply you need to use my code as
Note : This line of code automatic open the dialog box if Location is not on. This piece of line is used in Google Map also
public class MainActivity extends AppCompatActivity
implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
PendingResult<LocationSettingsResult> result;
final static int REQUEST_LOCATION = 199;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
mGoogleApiClient.connect();
}
#Override
public void onConnected(Bundle bundle) {
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(30 * 1000);
mLocationRequest.setFastestInterval(5 * 1000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
builder.setAlwaysShow(true);
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:
// 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(
MainActivity.this,
REQUEST_LOCATION);
} catch (SendIntentException e) {
// Ignore the error.
}
break;
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.
//...
break;
}
}
});
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
Log.d("onActivityResult()", Integer.toString(resultCode));
//final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);
switch (requestCode)
{
case REQUEST_LOCATION:
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;
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
}
Note : This line of code automatic open the dialog box if Location is not on. This piece of line is used in Google Map also
Since Android version 4.4, you can't enable/disable gps programatically. If you try the code proposed on this answer, an exception will be fired.
java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.location.GPS_ENABLED_CHANGE
Above correct answer is very old it needs something new so Here is answer
As in last update we have androidx support so first include dependency in your app level build.gradle file
implementation 'com.google.android.gms:play-services-location:17.0.0'
then add in your manifest file:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
don't forget to take user consent for these permissions if you are releasing
now here is code just use it
protected void createLocationRequest() {
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setInterval(10000);
locationRequest.setFastestInterval(5000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
SettingsClient client = LocationServices.getSettingsClient(this);
Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());
task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
// All location settings are satisfied. The client can initialize
// location requests here.
// ...
Toast.makeText(MainActivity.this, "Gps already open",
Toast.LENGTH_LONG).show();
Log.d("location settings",locationSettingsResponse.toString());
}
});
task.addOnFailureListener(this, 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(MainActivity.this,
REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sendEx) {
// Ignore the error.
}
}
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==REQUEST_CHECK_SETTINGS){
if(resultCode==RESULT_OK){
Toast.makeText(this, "Gps opened", Toast.LENGTH_SHORT).show();
//if user allows to open gps
Log.d("result ok",data.toString());
}else if(resultCode==RESULT_CANCELED){
Toast.makeText(this, "refused to open gps",
Toast.LENGTH_SHORT).show();
// in case user back press or refuses to open gps
Log.d("result cancelled",data.toString());
}
}
}
if something goes wrong please ping me
Short and easy solution with newest API, from https://developer.android.com/training/location/change-location-settings.html.
You will get nice Google AlertDialog with ok button without any need of going to settings.
Straight to the point. My code in Fragment:
override fun onResume() {
super.onResume()
checkGPSEnabled()
}
private fun checkGPSEnabled() {
val manager = requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (manager.isProviderEnabled(LocationManager.GPS_PROVIDER).not()) {
turnOnGPS()
}
}
private fun turnOnGPS() {
val request = LocationRequest.create().apply {
interval = 2000
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
val builder = LocationSettingsRequest.Builder().addLocationRequest(request)
val client: SettingsClient = LocationServices.getSettingsClient(requireActivity())
val task: Task<LocationSettingsResponse> = client.checkLocationSettings(builder.build())
task.addOnFailureListener {
if (it is ResolvableApiException) {
try {
it.startResolutionForResult(requireActivity(), 12345)
} catch (sendEx: IntentSender.SendIntentException) {
}
}
}.addOnSuccessListener {
//here GPS is On
}
}
That's it. Just copy and paste. You will need also:
implementation 'com.google.android.gms:play-services-location:18.0.0' and in Manifest <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
An answer was developed in another question, but it was closed, and I'd like the community to try it out as well.
boolean gpsStatus = locmanager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (!gpsStatus) {
Settings.Secure.putString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "network,gps");
}
See this comment
This solution would require the WRITE_SETTINGS and WRITE_SECURE_SETTINGS permissions.
Maybe with reflection tricks around the class android.server.LocationManagerService.
Also, there is a method (since API 8) android.provider.Settings.Secure.setLocationProviderEnabled
This is the best solution provided by Google Developers. Simply call this method in onResume of onCreate after initializing GoogleApiClient.
private void updateMarkers() {
if (mMap == null) {
return;
}
if (mLocationPermissionGranted) {
// Get the businesses and other points of interest located
// nearest to the device's current location.
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API).build();
mGoogleApiClient.connect();
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(10000);
locationRequest.setFastestInterval(10000 / 2);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
builder.setAlwaysShow(true);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest
.Builder()
.addLocationRequest(mLocationRequest);
PendingResult<LocationSettingsResult> resultPendingResult = LocationServices
.SettingsApi
.checkLocationSettings(mGoogleApiClient, builder.build());
resultPendingResult.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(#NonNull LocationSettingsResult locationSettingsResult) {
final Status status = locationSettingsResult.getStatus();
final LocationSettingsStates locationSettingsStates = locationSettingsResult.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 this can be fixed
// by showing the user a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
status.startResolutionForResult(
MainActivity.this,
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
} catch (IntentSender.SendIntentException e) {
// Ignore the error.
}
break;
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.
break;
}
}
});
#SuppressWarnings("MissingPermission")
PendingResult<PlaceLikelihoodBuffer> result = Places.PlaceDetectionApi
.getCurrentPlace(mGoogleApiClient, null);
result.setResultCallback(new ResultCallback<PlaceLikelihoodBuffer>() {
#Override
public void onResult(#NonNull PlaceLikelihoodBuffer likelyPlaces) {
for (PlaceLikelihood placeLikelihood : likelyPlaces) {
// Add a marker for each place near the device's current location, with an
// info window showing place information.
String attributions = (String) placeLikelihood.getPlace().getAttributions();
String snippet = (String) placeLikelihood.getPlace().getAddress();
if (attributions != null) {
snippet = snippet + "\n" + attributions;
}
mMap.addMarker(new MarkerOptions()
.position(placeLikelihood.getPlace().getLatLng())
.title((String) placeLikelihood.getPlace().getName())
.snippet(snippet));
}
// Release the place likelihood buffer.
likelyPlaces.release();
}
});
} else {
mMap.addMarker(new MarkerOptions()
.position(mDefaultLocation)
.title(getString(R.string.default_info_title))
.snippet(getString(R.string.default_info_snippet)));
}
}
Note : This line of code automatic open the dialog box if Location is not on. This piece of line is used in Google Map also
status.startResolutionForResult(
MainActivity.this,
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
This code works on ROOTED phones:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] cmds = {"cd /system/bin" ,"settings put secure location_providers_allowed +gps"};
try {
Process p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
for (String tmpCmd : cmds) {
os.writeBytes(tmpCmd + "\n");
}
os.writeBytes("exit\n");
os.flush();
}
catch (IOException e){
e.printStackTrace();
}
}
}
For turning off GPS you can use this command instead
settings put secure location_providers_allowed -gps
You can also toggle network accuracy using the following commands:
for turning on use:
settings put secure location_providers_allowed +network
and for turning off you can use:
settings put secure location_providers_allowed -network
This one works for me.
It is a simpler solution than Rj0078's answer under this question, but that one is worked as well.
It shows a dialog like this:
(Written in Kotlin)
googleApiClient = GoogleApiClient.Builder(context!!)
.addApi(LocationServices.API).build()
googleApiClient!!.connect()
locationRequest = LocationRequest.create()
locationRequest!!.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
locationRequest!!.interval = 30 * 1000.toLong()
locationRequest!!.fastestInterval = 5 * 1000.toLong()
val builder = LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest!!)
builder.setAlwaysShow(true)
result =
LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build())
result!!.setResultCallback { result ->
val status: Status = result.status
when (status.statusCode) {
LocationSettingsStatusCodes.SUCCESS -> {
// Do something
}
LocationSettingsStatusCodes.RESOLUTION_REQUIRED ->
try {
startResolutionForResult(),
status.startResolutionForResult(
activity,
REQUEST_LOCATION
)
} catch (e: SendIntentException) {
}
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {
// Do something
}
}
}
Things have changed since this question was posted, now with new Google Services API, you can prompt users to enable GPS:
https://developers.google.com/places/android-api/current-place
You will need to request ACCESS_FINE_LOCATION permission in your manifest:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Also watch this video:
https://www.youtube.com/watch?v=F0Kh_RnSM0w
This is a more statble code for all Android versions and possibly for new ones
void checkGPS() {
LocationRequest locationRequest = LocationRequest.create();
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
SettingsClient settingsClient = LocationServices.getSettingsClient(this);
Task<LocationSettingsResponse> task = settingsClient.checkLocationSettings(builder.build());
task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
Log.d("GPS_main", "OnSuccess");
// GPS is ON
}
});
task.addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull final Exception e) {
Log.d("GPS_main", "GPS off");
// GPS off
if (e instanceof ResolvableApiException) {
ResolvableApiException resolvable = (ResolvableApiException) e;
try {
resolvable.startResolutionForResult(ActivityMain.this, REQUESTCODE_TURNON_GPS);
} catch (IntentSender.SendIntentException e1) {
e1.printStackTrace();
}
}
}
});
}
And you can handle the GPS state changes here
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == Static_AppVariables.REQUESTCODE_TURNON_GPS) {
switch (resultCode) {
case Activity.RESULT_OK:
// GPS was turned on;
break;
case Activity.RESULT_CANCELED:
// User rejected turning on the GPS
break;
default:
break;
}
}
}
You just need to remove the LocationListener from LocationManager
manager.removeUpdates(listener);
Use This code Simple and Easy to Access:
Permissions:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Follow this Code to access the GPS programmatically:
LocationManager locationManager ;
boolean GpsStatus ;
GPSStatus();
if(GpsStatus == true)
{
textview.setText("Your Location Services Is Enabled");
}else
{textview.setText("Your Location Services Is Disabled");}
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
public void GPSStatus(){
locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
GpsStatus = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
}
I have a CC2540 BLE kit and i want to see the battery level of the kit in my smartphone app. I have made the code, which gets the battery level from the kit. The battery level is called BodySensor in this case:
First, i will go into the characteristic value of the battery service part for the kit. So i use the Service and Characteristic UUID's for the battery service:
public void getBodySensorLoc(BluetoothDevice device)
{
Log.i(TAG, "getBodySensorLoc");
BluetoothGattService mHRP = mBluetoothGatt.getService(device, HRP_SERVICE);
if (mHRP == null)
{
Log.e(TAG, "getBodySensorLoc: mHRP = null");
return;
}
BluetoothGattCharacteristic mBSLcharac = mHRP.getCharacteristic(BODY_SENSOR_LOCATION);
if (mBSLcharac == null) {
Log.e(TAG, "getBodySensorLoc: mBSLcharac = null");
return;
}
mBluetoothGatt.readCharacteristic(mBSLcharac);
}
My purpose is to read the battery level, when pressing a button in my application. So i implement this button in my Activity class:
((Button) findViewById(R.id.btn_BSL)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
mService.getBodySensorLoc(mDevice);
}
});
This kit will automatically send the battery level back to the smartphone. So i will set focus on onCharacteristicRead method of BluetoothGattCallback part in my code:
private BluetoothGattCallback mGattCallbacks = new BluetoothGattCallback()
{
public void onCharacteristicRead(BluetoothGattCharacteristic charac, int status)
{
UUID charUuid = charac.getUuid();
Bundle mBundle = new Bundle();
Message msg = Message.obtain(mActivityHandler, HRP_VALUE_MSG);
Log.i(TAG, "onCharacteristicRead");
if (charUuid.equals(BODY_SENSOR_LOCATION))
mBundle.putByteArray(BSL_VALUE, charac.getValue());
msg.setData(mBundle);
msg.sendToTarget();
}
};
I want the application to show the received battery level in a textview. The kit sends the battery level as a integer, so if the level is 70%, it sends "70". The code includes a Handler in the Activity class:
private Handler mHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case HRPService.HRP_VALUE_MSG:
Log.d(TAG, "mHandler.HRP_VALUE_MSG");
Bundle data1 = msg.getData();
final byte[] bslval = data1.getByteArray(HRPService.BSL_VALUE);
runOnUiThread(new Runnable()
{
public void run()
{
if (bslval != null)
{
try {
Log.i(TAG, "BYTE BSL VAL =" + bslval[0]);
TextView bsltv = (TextView) findViewById(R.id.BodySensorLocation);
bsltv.setText("\t" + mContext.getString(R.string.BodySensorLocation)
+ getBodySensorLocation(bslval[0]));
} catch (Exception e)
{
Log.e(TAG, e.toString());
}
}
}
});
default:
super.handleMessage(msg);
}
}
};
The problem is that the textview doesn't show anything, when i press this button in my application after i connected my smartphone with the kit. Can anyone tell me, where the problem is ?.
Thanks in advance
Unsure what exact kit you have. Unsure if they all have battery level measuring hardware on board. Maybe this is the reason.