Device location is null on another device (GoogleMaps Activity) - java

I am currently working on my second android app which contains a google maps activity. In this activity I would like to show the user their current location. I kind of managed to do it and it works on both of my devices (Huawei P smart & Galaxy S5). I also sent my friend an APK of the app and on his device (Huawei P9 Lite) the current location returns null after calling task.getResult(). On his device the method will always jump to the else statement (meaning the currentLocation == null). I used the following method.
private void getDeviceLocation() {
Log.d(TAG, "getDeviceLocation: getting the devices current location");
try {
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
mFusedLocationProviderClient.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location currentLocation) {
Log.d(TAG, "onComplete: found location!");
if (currentLocation != null) {
moveCamera(new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude()),
DEFAULT_ZOOM);
} else {
Log.d(TAG, "onComplete: current location is null");
Toast.makeText(MapsActivity.this, "unable to get current location", Toast.LENGTH_SHORT).show();
}
}
});
} catch (SecurityException e) {
Log.e(TAG, "getDeviceLocation: SecurityException: " + e.getMessage());
}
}
I have tried/done the following things:
Adding all required permissions/features to my manifest
Trying some other solutions I found here, as far as I'm aware none of them were showing different results on different devices
Changing the minSDK to 17 (was 23 before).
Adding the nullcheck and try & catch
Because I'm having no problems on my own devices and can't find anything remarkable in my logcat's (since it's all working on my devices) it's kind of hard for me to understand why this is happening.

Related

How to update a database column based on the device's location?

I've been working on a map based app, and so far the application gets the data of markers from a Room database as a LiveData object and draws the markers on the map and gets the device's location through a FusedLocationProviderClient.
Now I have tried to create a method that would update a column in the database from 0 to 1 if the device reaches a marker, making the marker "active" and then displaying the marker's name as a toast if that marker's "active" column equals to 1.
So far I have tried to use SphericalUtil.computeDistanceBetween(LatLng1, LatLng2) < distance and if the condition is met, then it calls a method to update the column, but I have not managed to get it to work, as the devices location keeps changing and the markers come from a LiveData List object which are both checked for changes and I don't know how to use these in the computeDistanceBetween method. I have gone through the documents related to markers and other map based objects but so far I have not found a solution.
Here is the method that retrieves and draws the markers on the map.
markerViewModel.getAllMarkers().observe(this, new Observer<List<MarkerObject>>() {
#Override
public void onChanged(List<MarkerObject> markerObjects) {
for (MarkerObject markerObject : markerObjects) {
LatLng latLng = new LatLng(markerObject.getLatitude(), markerObject.getLongitude());
mMap.addMarker(new MarkerOptions()
.title(markerObject.getTitle())
.position(latLng)
.visible(true));
}
}
});
the methods that get and draw the device's location on the map.
/**
* Updates the map's UI settings based on whether the user has granted location permission.
*/
private void updateLocationUI() {
if (mMap == null) {
return;
}
getLocationPermission();
try {
if (locationPermissionGranted) {
mMap.setMyLocationEnabled(true);
mMap.getUiSettings().setMyLocationButtonEnabled(true);
} else {
mMap.setMyLocationEnabled(false);
mMap.getUiSettings().setMyLocationButtonEnabled(false);
lastKnownLocation = null;
}
} catch (SecurityException e) {
Log.e("Exception: %s", e.getMessage());
}
}
/**
* Gets the current location of the device, and positions the map's camera.
*/
public void getDeviceLocation() {
/*
* Get the best and most recent location of the device, which may be null in rare
* cases when a location is not available.
*/
try {
if (locationPermissionGranted) {
Task<Location> locationResult = fusedLocationProviderClient.getLastLocation();
locationResult.addOnCompleteListener(this, new OnCompleteListener<Location>() {
#Override
public void onComplete(#NonNull Task<Location> task) {
if (task.isSuccessful()) {
// Set the map's camera position to the current location of the device.
lastKnownLocation = task.getResult();
if (lastKnownLocation != null) {
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(lastKnownLocation.getLatitude(),
lastKnownLocation.getLongitude()), DEFAULT_ZOOM));
}
} else {
Log.d(TAG, "Current location is null. Using defaults.");
Log.e(TAG, "Exception: %s", task.getException());
mMap.moveCamera(CameraUpdateFactory
.newLatLngZoom(defaultLocation, DEFAULT_ZOOM));
mMap.getUiSettings().setMyLocationButtonEnabled(false);
}
}
});
}
} catch (SecurityException e) {
Log.e("Exception: %s", e.getMessage(), e);
}
}
I have tried to reach a solution for quite a while through many trials but to no success, I really hope someone can help because I am out of ideas. Any help is well appreciated. Also I don't ask for help in just any case but with this I really am struggling, so literally any documentation or piece of info that would help would be great.
This is something I have previously used to check the distance between location objects, you can use it as it is or modify it to your needs, the code is pretty straight forward.
public final boolean isLocationCloseEnough(Location currentLocation, Location markerLocation, double distance) {
// this is where the method stores the distance between the two locations
float[] distanceInMeters = new float[1];
Location.distanceBetween(currentLocation.getLatitude(), currentLocation.getLongitude(), markerLocation.getLatitude(), markerLocation.getLongitude(), distanceInMeters);
return (double)distanceInMeters[0] < distance;
}
To be able to request location updates you need a location Request like so and request location updates
LocationRequest locationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY).setInterval(5);
LocationCallback callback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
// here is the location
Location lastLocation = locationResult.getLastLocation();
// do what needs to be done
}
};
public void sample() {
FusedLocationProviderClient client = LocationServices.getFusedLocationProviderClient(context);
client.requestLocationUpdates(locationRequest, callback, Looper.getMainLooper());
}
Finally when your activity or fragment pauses make sure to remove/stop the updates like so
client.removeLocationUpdates(callback)
You can find more information on LocarionRequest here, and play around with its configurations, https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest

AppUpdateManager doesn't install app when completeUpdate() is called

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);

Force stopping LE Scan while BT Adapter is OFF thows java.lang.IllegalStateException (IN NEXUS 5 and Android 6)

I am facing this error while disabling Bluetooth. Googled it but did not find solution. Here is my broadcast receiver which invokes when bluetooth state is changed.
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
Log.e(LOG_TAG, "Broadcast receiver - onReceive");
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
h.removeCallbacks(runnable);
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
switch (state) {
case BluetoothAdapter.STATE_OFF:
Log.i(LOG_TAG, "***** BLE-Bluetooth is disabled");
Toast.makeText(getApplicationContext(), "Bluetooth is disabled", Toast.LENGTH_LONG).show();
Log.i(TAG, "***** mBeaconScanner "+ mBeaconScanner);
if(null != mBeaconScanner)
mBeaconScanner.scanLeDevice(false);
break;
case BluetoothAdapter.STATE_ON:
Log.i(LOG_TAG, "***** BLE-Bluetooth is enabled");
Toast.makeText(getApplicationContext(), "Bluetooth is enabled", Toast.LENGTH_LONG).show();
if(null != mBeaconScanner)
mBeaconScanner.scanLeDevice(true);
break;
}
}
}
};
In the above code I am trying to stop ble scanning while disabling the Bluetooth. In the above code method "mBeaconScanner.scanLeDevice(false);" redirects to :
Log.i(TAG, "***** Stopping BLE Scan for Android version " + Build.VERSION.SDK_INT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (bluetoothLeScanner != null)
{
bluetoothLeScanner.stopScan(mScanCallback);
}
} else {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
In the above snippet I am getting Exception when calling bluetoothLeScanner.stopScan(mScanCallback) method.
NOTE: this issue is not reproducible in all the devices but nexus and its not very frequently reproducible as well for me.
Please suggest me if there is any solution for this.. Thanks in advance
The only solution I can suggest here is comment this code:-
//mBeaconScanner.scanLeDevice(false);
The way BLE scan works is pretty complicated at the radio level. There are tons of factors (like power, efficiency etc..) that are taken into consideration while arriving at the right scan window sleep time etc..
For you in this particular case when the BT adapter itself is turned OFF, trying to stop scan is an invalid operation as far as the radio is concerned. Am glad that Android FW throws this exception !! Just get rid of this code and may be do some internal app specific state transition (if you have to) or else just log and be done in case BluetoothAdapter.STATE_OFF:

Android mp4 videos doesn't play in Emulator as well as device

I want to stream mp4 videos from my Android phone in my Android app. The videos are stored in a server. All I have is their URL's. I tried the code below, but it didn't play my videos (it worked fine with .3gp videos on both the emulator and the device) I'm using Galaxy Y hardware and the emulator is 4.2 version of Android. Please don't refer to me any links, I honestly did a lot of searching but all of it got in vain. I can't use WebView, I have to use VideoView in my app.
The code is:
private void playVideo() {
try {
final String path = mPath.getText().toString();
Log.v(TAG, "path: " + path);
if (path == null || path.length() == 0) {
Toast.makeText(MainActivity.this, "File URL/path is empty",
Toast.LENGTH_LONG).show();
} else {
// If the path has not changed, just start the media player
if (path.equals(current) && mVideoView != null) {
mVideoView.start();
mVideoView.requestFocus();
return;
}
current = path;
mVideoView.setVideoPath(getDataSource(path));
mVideoView.start();
mVideoView.requestFocus();
}
} catch (Exception e) {
Log.e(TAG, "error: " + e.getMessage(), e);
if (mVideoView != null) {
mVideoView.stopPlayback();
}
}
}
Where path is initialized to a link:
path = http://download.itcuties.com/teaser/itcuties-teaser-480.mp4
Any help would be highly appreciated.

Unable to get current GPS Location co-ordinates

I have been trying hard to get my current location's GPS co-ordinates but my app never locks on to a GPS satellite.
The GPS icon in the notification area just keeps on blinking.
Whereas I tried using Google Maps on Android (the pre-installed app) and that thing is able to lockon in approx 60 secs! In both of the cases my 3G data connection was switched on and working.
Update: I am using Android 2.3.3 (HTC Desire S (Factory installed OS; no updates applied)) Logcat output is here. Now this is without setting LocationUpdates()'s min time and min-distance between update to 0, 0.
Update #2: My earlier code is here(PasteBin Link).
Update #3: Now, I am getting a force close after displaying a Toast .."Available".. in on onStatusChanged().
Update #4: Finally..I got it to work.
--
So, is it like that the Google map's app uses some proprietary code for locking on to GPS signals? I have tried using various version of my code. Tried using criteria(s) but never got them to work with GPS. For me getting precise (~50ft accuracy) location co-ordinates through GPS is a must.
My Code:
public class LocationDemoActivity extends Activity implements LocationListener {
LocationManager locationManager;
StringBuilder builder;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000l, 50.0f, this);
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
locationManager.removeUpdates(this);
locationManager = null;
Intent i = new Intent(
android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(i);
}
#Override
public void onLocationChanged(Location location) {
// builder = new StringBuilder();
double lati=location.getLatitude();
double longi=location.getLongitude();
double alti=location.getAltitude();
float acc=location.getAccuracy();
float speed=location.getSpeed();
long time=location.getTime();
System.out.println(lati);
System.out.println(longi);
System.out.println(alti);
System.out.println(acc);
System.out.println(speed);
System.out.println(time);
/*Toast.makeText(this, "Lati: " + lati,Toast.LENGTH_SHORT).show();
Toast.makeText(this, "Long: " + longi,Toast.LENGTH_SHORT).show();
Toast.makeText(this, "Alti: " + alti,Toast.LENGTH_SHORT).show();
Toast.makeText(this, "Acc.: " + acc,Toast.LENGTH_SHORT).show();
Toast.makeText(this, "Speed: " + speed,Toast.LENGTH_SHORT).show();
Toast.makeText(this, "Time: " + time,Toast.LENGTH_SHORT).show();*/
builder.append("Longitide: " + location.getLongitude());
builder.append('\n');
builder.append("Latitude: " + location.getLatitude());
builder.append('\n');
builder.append("Altitude: " + location.getAltitude());
builder.append('\n');
builder.append("Accuracy: " + location.getAccuracy());
builder.append('\n');
builder.append("TimeStamp:" + location.getTime());
builder.append('\n');
System.out.println(builder.toString());
Toast.makeText(this, builder.toString(), Toast.LENGTH_LONG).show();
}
#Override
public void onProviderDisabled(String provider) {
System.out.println("Provider Disabled:");
Intent intent = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
#Override
public void onProviderEnabled(String provider) {
System.out.println("Provider Enabled:");
Toast.makeText(this, "GPS is now enabled...", Toast.LENGTH_LONG).show();
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
switch (status) {
case LocationProvider.OUT_OF_SERVICE:
System.out.println("Status Changed: Out of Service");
Toast.makeText(this, "Status Changed: Out of Service",
Toast.LENGTH_SHORT).show();
break;
case LocationProvider.TEMPORARILY_UNAVAILABLE:
System.out.println("Status Changed: Temporarily Unavailable");
Toast.makeText(this, "Status Changed: Temporarily Unavailable",
Toast.LENGTH_SHORT).show();
break;
case LocationProvider.AVAILABLE:
System.out.println("Status Changed: Available");
Toast.makeText(this, "Status Changed: Available",
Toast.LENGTH_SHORT).show();
break;
}
}
}
Please do answer as it's quite urgent on me and any help is greatly appreciable :)
Thanks..
It seams pretty obvious that you won't get any Location updates, because you have set the minDistance to 50 meters or 164.042 ft. It appears you have confused this with accuracy.
The minDistance parameter is the minimum distance between location updates. So you would have to move at least 50 meters to get a location update.
Also make sure you have a clear view of the sky in order to have GPS signal.
Read more in the documentation
http://developer.android.com/reference/android/location/LocationManager.html
I asked a related question here.
To me looks like your GPS on the phone is not able to see the sat's. You need to get our of your office/home onto open air. In my case, I moved to NetworkProvider since GPS was just too clumsy.
Also note, that the parameters you give for distance and time are not literal, its the best guess that the api makes. So dont count on response times/distances from the API callback.
Do you have all these manifest permissions?
ACCESS_COARSE_LOCATION
ACCESS_FINE_LOCATION
ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_MOCK_LOCATION
CONTROL_LOCATION_UPDATES
INTERNET

Categories