I have this method, which manages my location:
#Override
public void onLocationChanged(final Location location) {
if(inRun){
Clocation myLocation = new Clocation(location, this.useMetricUnits());
this.updateSpeed(myLocation);
this.updateDistance(myLocation);
this.updateAverageSpeed(this.distance, this.chronometer);
if (activity.getText().toString() != ActivityRecongnizedService.getActivity()) {
activity.setText(ActivityRecongnizedService.getActivity());
activityTimer.start();
}
switch (activity.getText().toString()) {
case "STILL": still = true; break;
case "IN VEHICLE": inVehicle = true; break;
case "ON BICYCLE": onBicycle = true; break;
case "ON FOOT": onFoot = true; break;
case "RUNNING": running = true; break;
case "WALKING": walking = true;break;
case "TILTING": tilting = true; break;
}
setTimeActivity();
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
String[] key;
key = user.getEmail().split("#");
reference.child("Position").child(key[0]).child("latlng").setValue(new LatLng(location.getLatitude(),location.getLongitude()));
}
}
But I want this method to run when MainActivity is down. I read about this thing and there are two ways to do the same: with service or with onStop method.
I prefer the second way, with onStop method, but I don't know how to call onLocationChanged in onStop method.
I hope this could help you.
In Android, there are location manager, which provides access to system location service.
You can fire onLocationChanged event by using this class.
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
// Get the best provider for the criteria
Criteria criteria = new Criteria();
criteria.setPowerRequirement(Criteria.POWER_LOW);
criteria.setAccuracy(Criteria.ACCURACY_FINE);
String bestprovider = locationManager.getBestProvider(criteria,false);
locationManager.requestLocationUpdates(bestprovider,0, 0, this);
If you insert some of this code in onStop method, the onLocationChanged event will be fired.
Override your onStop method and get the user's last known location in this manner
fusedLocationClient.lastLocation
.addOnSuccessListener { location : Location? ->
// Got last known location. In some rare situations this can be null.
}
refer this link for more detail https://developer.android.com/training/location/retrieve-current now that you got the user's location under the call back of onSuccessListener you can update the location to your Firebase Database/Server
Note Depending on your requirements you can run this code on a main thread or on a different thread
Related
can you help me. i have an error in my code with a boolean isFromMockProvider() on a null object reference. this problem occurs when the gps on my provider is slow can you guys help me with dealing with the error
here is my code:
GetLocation getLocation = new GetLocation(getApplicationContext());
Location location = getLocation.getLocation();
boolean isMockLocation = location.isFromMockProvider();
if (isMockLocation==true){
showDialog();
}
else {
tesmock.setText("No Use Mock ");
}
Your question is lacking quite a bit of context, so this involves some guess work:
What's probably happening is that when your gps is slow, getLocation.getLocation() returns null rather than a Location object, so trying to call location.isFromMockProvider() throws a NullPointerException.
The best way to solve this would be to check whether location is null before calling that function:
Location location = getLocation.getLocation();
if(location!=null){
boolean isMockLocation = location.isFromMockProvider();
//the stuff you then do with isMockLocation
} else{
//display an error message or something saying the GPS is too slow
}
Is it like this? I'm sorry because I'm a beginner
Location location = getLocation.getLocation();
if(location!=null){
boolean isMockLocation = location.isFromMockProvider();
if (isMockLocation==true){
showDialog();
}
else {
tesmock.setText("No Use Mock ");
}
} else{
//display an error message or something saying the GPS is too slow
}
You are using 2 If statements
GetLocation getLocation = new GetLocation(getApplicationContext());
Location location = getLocation.getLocation();
if (location!=null){
boolean isMockLocation = location.isFromMockProvider();
if (isMockLocation==true){
showDialog();
}
else {
tesmock.setText("No Use Mock ");
}
} else { //show Here a dialog saying GPS is slow or Something like this
}
After several (unsuccessful) attempts to make my applications compliant about the background access to the location, I decided to re-structure my code in order to remove the ACCESS_BACKGROUND_LOCATION permission from the manifest.
My application necessarily needs to get the location of the device at certain times (specifically I need the coordinates), what I'm interested in knowing is:
without using the permission mentioned above, how do I get, in foreground, the location of the device?
is it possible to do it with a one-time call without using services etc?
I thought about using this code, do you think it could be enough?
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if (location != null) {
// Logic to handle location object
}
}
});
or something like this:
LocationManager mLocationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE);
List<String> providers = mLocationManager.getProviders(true);
Location bestLocation = null;
for (String provider : providers) {
Location location = mLocationManager.getLastKnownLocation(provider);
if (location == null) {
continue;
}
if (bestLocation == null || location.getAccuracy() < bestLocation.getAccuracy()) {
bestLocation = location;
}
}
is there a better way to do this?
To get the last know location you need to have following permissions declared in Manifest file.
"android.permission.ACCESS_FINE_LOCATION"
Then you may use Fused Location Provider as you have used.
Now if you want periodic updates you may want to register for those updates using following callback.
requestLocationUpdates
passed with a request object and callback to receive updates.
Helpful links with exact code: Request Updates
I’m trying to write a utility class to wrap the Google Play Services FusedLocationProviderClient API and location permissions request as I’m sick of writing all that boilerplate every time I want to add location functionality to an app. The problem I’m having though is I’m unable to remove location updates once I’ve started them. Here’s the relevant bits of my utility class:
public class UserLocationUtility extends LocationCallback
{
// Hold a WeakReference to the host activity (allows it to be garbage-collected to prevent possible memory leak)
private final WeakReference<Activity> weakActivity;
// Debug tag
private static final String TAG = "UserLocationUtility";
public static class RequestCodes
{
static final int CURRENT_LOCATION_ONE_TIME = 0;
static final int CURRENT_LOCATION_UPDATES = 1;
static final int LAST_KNOWN_LOCATION = 2;
static final int SMART_LOCATION = 3;
}
private FusedLocationProviderClient mLocationClient;
private Context mContext;
private LocationRequest mLocationRequest;
/* Constructor */
UserLocationUtility(Activity activity){
// assign the activity to the weak reference
this.weakActivity = new WeakReference<>(activity);
// Hold a reference to the Application Context
this.mContext = activity.getApplicationContext();
// Instantiate our location client
this.mLocationClient = LocationServices.getFusedLocationProviderClient(mContext);
// Set up the default LocationRequest parameters
this.mLocationRequest = new LocationRequest();
setLocationRequestParams(2000, 500, LocationRequest.PRIORITY_HIGH_ACCURACY);
// Sets up the LocationRequest with an update interval of 30 seconds, a fastest
// update interval cap of 5 seconds and using balanced power accuracy priority.
} /* Note: values for testing only. Will be dialed back for better power management when testing complete */
/* Stripped out other methods for brevity */
#SuppressLint("MissingPermission")
public void getCurrentLocationOneTime(final UserLocationCallback callback){
mLocationClient.requestLocationUpdates(mLocationRequest, new LocationCallback()
{
#Override
public void onLocationResult(LocationResult locationResult){
if (locationResult == null){
callback.onFailedRequest("getCurrentLocationOneTime(): Request failed: returned null");
return;
}
callback.onLocationResult(locationResult.getLastLocation());
stopLocationUpdates(); /* Stopping location updates here just for testing (NOT WORKING!!) */
}
}, null);
}
public void stopLocationUpdates(){
mLocationClient.removeLocationUpdates(new LocationCallback(){});
Log.i(TAG, "stopLocationUpdates(): Location updates removed");
}
}
Here’s how I’m trying to use it (from MainActivity):
UserLocationUtility locationUtility;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationUtility = new UserLocationUtility(this);
if (locationUtility.checkPermissionGranted()){
Log.i(TAG, "Permissions are granted.");
getLocationUpdates();
} else {
Log.i(TAG, "Permissions are not granted. Attempting to request...");
locationUtility.requestPermissions(UserLocationUtility.RequestCodes.CURRENT_LOCATION_UPDATES);
}
}
public void getLocationUpdates(){
locationUtility.getCurrentLocationOneTime(new UserLocationCallback() {
#Override
public void onLocationResult(Location location) {
Log.i(TAG, "getLocationUpdates result: " + location.toString());
}
#Override
public void onFailedRequest(String result) {
Log.e(TAG, "LocationUpdates result: " + result);
}
});
}
And here's a sample from the log:
I/MainActivity: getLocationUpdates result: Location[fused 34.421998,-125.084000 hAcc=731 et=+2h10m52s694ms vAcc=??? sAcc=??? bAcc=???]
I/UserLocationUtility: stopLocationUpdates(): Location updates removed
I/MainActivity: getLocationUpdates result: Location[fused 34.421998,-125.084000 hAcc=739 et=+2h10m57s697ms vAcc=??? sAcc=??? bAcc=???]
I/UserLocationUtility: stopLocationUpdates(): Location updates removed
I/MainActivity: getLocationUpdates result: Location[fused 34.421998,-125.084000 hAcc=763 et=+2h11m5s723ms vAcc=??? sAcc=??? bAcc=???]
I/UserLocationUtility: stopLocationUpdates(): Location updates removed
etc...
As you can see I’m receiving the location updates correctly but the call to stopLocationUpdates() isn’t working. I have a feeling it’s something to do with the fact that I’m passing a new LocationCallback to the removeUpdates() method, but I’m not sure what the alternative is, or even if there is an alternative. This being a non-activity class I can’t exactly initialise LocationCallback as a member in onCreate() then pass it around as needed. The google docs on this aren’t much help at all. Whether that’s because I lack the necessary understanding to decipher them or because they’re just not very good I don’t know but either way I’m stumped and having searched around a lot I can’t seem to find an existing answer elsewhere.
Thanks.
Posting my solution as an answer in case it helps anyone else.
I got it working by declaring a LocationCallback as a member variable and then initialising (or re-initialising) it in each method that requires it...
public void getCurrentLocationUpdates(final UserLocationCallback callback){
if (mIsReceivingUpdates){
callback.onFailedRequest("Device is already receiving updates");
return;
}
// Set up the LocationCallback for the request
mLocationCallback = new LocationCallback()
{
#Override
public void onLocationResult(LocationResult locationResult){
if (locationResult != null){
callback.onLocationResult(locationResult.getLastLocation());
} else {
callback.onFailedRequest("Location request returned null");
}
}
};
// Start the request
mLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, null);
// Update the request state flag
mIsReceivingUpdates = true;
}
I check at the beginning of the method whether or not location updates are already being received and get out early if so. This prevents duplicate (and thus unstoppable) location update requests being initiated.
Calling the stopLocationUpdates (below for reference) method now works as it should.
public void stopLocationUpdates(){
mLocationClient.removeLocationUpdates(mLocationCallback);
mIsReceivingUpdates = false;
Log.i(TAG, "Location updates removed");
}
I am trying to develop a feature for an app where you have a list of "codes" that you enter and that are dialed one by one. I have looked over TelephonyManager and followed a tutorial on developing a broadcast receiver with a listener for responses but it does not always work as it should.
One idea was to store all the numbers necessary in SharedPref. If the Activity (only created for the intent towards dialer) went into onStop() (meaning that above, the dialer screen was on) and then into onResume() (call ended and activity resumed), I would remove the number last dialed from the SharedPref and then, if any remained, open the dialer again. The broadcast made sure than once the state flow of the TelephonyManager was "OFFHOOK => IDLE", it would return the user to the Activity . Short story, it did not always perform as it should have.
How should I tackle the problem ?
EDIT
My curent solution was to
Create a doPhoneCall() function that would handle the intent creation and deployment itself.
#Override
protected void doPhoneCall(){
super.onResume();
wentIntoCall = false;
/** More code here for dialing */
}
Place this function into the onResume(). Even if the onResume will be called multiple times, the wentIntoCall boolean will make sure that the function won't be called multiple times.
#Override
protected void onResume() {
super.onResume();
if(wentIntoCall)
doPhoneCall();
}
Having in mind that after a call, the phone should return to its previous state, so it would return to the Activity in which we are doing are call, we will add to the activity a CallListener, and in the case of IDLE, based on the tutorial linked above, we make the wentIntoCall be true. ( The activity will go into onResume() and, upon seeing that the boolean is true, it will initialize the next call ).
case TelephonyManager.CALL_STATE_IDLE:
Log.e(TAG, "CALL_STATE_IDLE==>"+incoming_number);
if((prev_state == TelephonyManager.CALL_STATE_OFFHOOK)){
prev_state=state;
wentIntoCall = true;
//Answered Call which is ended
}
if((prev_state == TelephonyManager.CALL_STATE_RINGING)){
prev_state=state;
wentIntoCall = true;
//Rejected or Missed call
}
My final question : is this the right way to handle this functionality, or should I try to come up with another implementation of it ?
EDIT 2
Looks like my "codes", being USSD codes, are not behaving like normal phone calls.. So for normal phone calls the code above seems to work, but for dialing codes, not that much. I have "downgraded" my solution to a simple for-loop. Seems to be working fine now.
I dont know for android O , but for android 6.0 > You cant detect answer in direct way . Call no exist number and see PhoneStateListener what will trigger in one case and track successed call also.
Make public static array , add all your numbers intro array .
I made services . Insert permissions in manifest make your own action also ( NEXT_CALL for example ) .
Than easy make intent for startServices :
SharedPreferences settings;
SharedPreferences.Editor SAVES;
Intent serviceIntent = new Intent(MainActivity.this, ServiceForCalls.class);
serviceIntent.setAction("xxx.xxx.NEXT_CALL");
startService(serviceIntent);
isCalling = true;
SAVES.putBoolean( "isCalling" , isCalling );
SAVES.commit();
SAVES.apply();
You must use timeout interval about 10 sec for next call.
Heres little help func - end call and phoneState handler :
void END_CALL () throws InvocationTargetException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException {
tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
Class c = null;
try {
c = Class.forName(tm.getClass().getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Method m = null;
try {
m = c.getDeclaredMethod("getITelephony");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
m.setAccessible(true);
Object telephonyService = m.invoke(tm); // Get the internal ITelephony object
c = Class.forName(telephonyService.getClass().getName()); // Get its class
m = c.getDeclaredMethod("endCall"); // Get the "endCall()" method
m.setAccessible(true); // Make it accessible
m.invoke(telephonyService); // invoke endCall()
if ( SIGNAL_STOP == false ) {
timerHandlerServicesStartNewNumber.postDelayed(timerRunnableServicesStartNewNumber, 1000);
}
}
private class PhoneStateChangeListener extends PhoneStateListener {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch(state){
case TelephonyManager.CALL_STATE_RINGING:
Log.println( Log.INFO , "RINGING" , "SERVICES%%%%%%%%%%%%%%%%RINGING%%%%%%%%%%%%%%%%%%");
wasRinging = true;
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.println( Log.INFO , "OFFHOOK BROADCAST" , "SERVICES%%%%%%%%%%%%%%%%%%%%%%%%");
if (!wasRinging) {
// Start your new activity
Log.println( Log.INFO , "OFFHOOK BROADCAST" , "SERVICES%%%%%%%%%%%%%%%%%%%%%%%");
if (SIGNAL_STOP == false) {
timerHandlerServices.postDelayed(timerRunnableServices, 10000);
}
} else {
// Cancel your old activity
Log.println( Log.INFO , "OFFHOOK BROADCAST" , "SERVICES%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
}
// this should be the last piece of code before the break
wasRinging = true;
break;
case TelephonyManager.CALL_STATE_IDLE:
Log.println( Log.INFO , "IDLE BROADCAST" , "SERVICES%%%%%%%%%%%%%%%%%IDLE%%%%%%%%%%%%%%%%%%%");
// this should be the last piece of code before the break
wasRinging = false;
break;
}
}
}
Thanks for : "meaning that above, the dialer screen was on" nice catch.
As a side note, in the Android O developer preview there is a new API which allows you to send a USSD request and register a callback to receive its results. For newer versions of Android this might meet your needs better.
I am testing an app which uses Location services. And it returns null causing NPE (Null Pointer Exception) whenever my Location Services are turned off. So after some searching I found that
isGPSEnabled = locationManager.isProviderEnabled(locationManager.GPS_PROVIDER);
should return the correct boolean value but when testing my app it seems to always return true causing a NPE (Null Pointer Exception) and crashing my app.
I also read this question. Which has the exact opposite problem apparently and tried that solution. That also didn't work. I am testing on a Samsung G5. Why is this happening. Is something wrong in the code or is there another solution to my problem.
Here is the code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
isGPSEnabled = false;
intentThatCalled = getIntent();
String m2txt = intentThatCalled.getStringExtra("v2txt");
getLocation(m2txt);
}
public void getLocation(String n2txt) {
locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
criteria = new Criteria();
bestProvider = String.valueOf(locationManager.getBestProvider(criteria, true)).toString();
location = locationManager.getLastKnownLocation(bestProvider);
isGPSEnabled = locationManager.isProviderEnabled(locationManager.GPS_PROVIDER);
if (isGPSEnabled==true) {
Log.e("TAG", "GPS is on");
latitude = location.getLatitude();
longitude = location.getLongitude();
Toast.makeText(PlacesDecoder.this, "latitude:" + latitude + " longitude:" + longitude, Toast.LENGTH_SHORT).show();
searchNearestPlace(n2txt);
}
}
I am still a beginner in android.
Please do help.
EDIT:
This question seems to have the same problem on the same Hardware model. Is this a Hardware Bug? If it is, is there any other possibility. I will also test on another device Note-4 and let you know.
The solution to your problem is to NEVER assume you have a location, Just because your GPS is enabled does not mean you will get a location.
At any time you can get a null location so instead of worrying about if the GPS is enabled or not you should worry about if your location returned is null or not.
getLastKnownLocation() can return a null if there is no last location