Android, get the location when the screen is off - android

I use a started service with the fused api, and implement the location listener directly on it.
The Location keeps updating even when the screen is locked, But it stops if the screen goes off.
So, is there any way to make sure that the location will keep updating when the screen is off?
I read a lot of other questions and I don't really know what i'm missing.
public class CLocationService extends Service implements GoogleApiClient.ConnectionCallbacks, LocationListener,
GoogleApiClient.OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
private PowerManager.WakeLock mWakeLock;
private LocationRequest mLocationRequest;
// Flag that indicates if a request is underway.
private boolean mInProgress;
private Boolean servicesAvailable = false;
private boolean isStarted;
public static final int LOCATION_SERVICE_NOTIFICATION_ID = 4567654;
private void showNotification() {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new Notification.Builder(this)
.setContentTitle(getText(R.string.app_name))
.setContentText("")
.setSmallIcon(R.mipmap.ic_notification)
.setContentIntent(pendingIntent)
.setTicker("")
.build();
startForeground(LOCATION_SERVICE_NOTIFICATION_ID, notification);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
/*
* Create a new location client, using the enclosing class to
* handle callbacks.
*/
setUpLocationClientIfNeeded();
startLocationServices();
}
/*
* Create a new location client, using the enclosing class to
* handle callbacks.
*/
protected synchronized void buildGoogleApiClient() {
this.mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
private boolean servicesConnected() {
// Check that Google Play services is available
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
// If Google Play services is available
if (ConnectionResult.SUCCESS == resultCode) {
return true;
} else {
return false;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
PowerManager mgr = (PowerManager) getSystemService(Context.POWER_SERVICE);
/*
WakeLock is reference counted so we don't want to create multiple WakeLocks. So do a check before initializing and acquiring.
This will fix the "java.lang.Exception: WakeLock finalized while still held: MyWakeLock" error that you may find.
*/
if (this.mWakeLock == null) { //**Added this
this.mWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
}
if (!this.mWakeLock.isHeld()) { //**Added this
this.mWakeLock.acquire();
}
if (!servicesAvailable || mGoogleApiClient.isConnected() || mInProgress)
return START_STICKY;
setUpLocationClientIfNeeded();
if (!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() && !mInProgress) {
mInProgress = true;
mGoogleApiClient.connect();
}
return START_STICKY;
}
private void setUpLocationClientIfNeeded() {
if (mGoogleApiClient == null)
buildGoogleApiClient();
}
#Override
public void onDestroy() {
stopLocationServices();
super.onDestroy();
}
private void startLocationServices() {
mInProgress = false;
// Create the LocationRequest object
mLocationRequest = LocationRequest.create();
// Use high accuracy
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the update interval to 5 seconds
mLocationRequest.setInterval(5000);
// Set the fastest update interval to 1 second
mLocationRequest.setFastestInterval(1000);
mLocationRequest.setSmallestDisplacement(0);
servicesAvailable = servicesConnected();
}
private void stopLocationServices() {
// Turn off the request flag
this.mInProgress = false;
if (this.servicesAvailable && this.mGoogleApiClient != null) {
this.mGoogleApiClient.unregisterConnectionCallbacks(this);
this.mGoogleApiClient.unregisterConnectionFailedListener(this);
this.mGoogleApiClient.disconnect();
// Destroy the current location client
this.mGoogleApiClient = null;
}
// Display the connection status
// Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ":
// Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
if (this.mWakeLock != null) {
this.mWakeLock.release();
this.mWakeLock = null;
}
}
private void cancelNotification() {
NotificationManager nMgr = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
nMgr.cancel(LOCATION_SERVICE_NOTIFICATION_ID);
}
#Override
public void onLocationChanged(Location location) {
// log the new location
}
#Override
public void onConnected(#Nullable Bundle bundle) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(this.mGoogleApiClient,
mLocationRequest, this); // This is the changed line.
}
#Override
public void onConnectionSuspended(int i) {
// Turn off the request flag
mInProgress = false;
// Destroy the current location client
mGoogleApiClient = null;
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
mInProgress = false;
/*
* Google Play services can resolve some errors it detects.
* If the error has a resolution, try sending an Intent to
* start a Google Play services activity that can resolve
* error.
*/
if (connectionResult.hasResolution()) {
// If no resolution is available, display an error dialog
} else {
}
}
}

I'm not sure I have your answer but since you're 9 days in with nothing I'll give some suggestions.
My app is doing what you would like to do. I use a long running started Service to keep location updated even when the phone is off.
The difference most likely to cause different behavior between your code & mine is the return from onStartCommand(). You are returning START_STICKY. This is the recommended return for something like this:
This mode makes sense for things that will be explicitly started and
stopped to run for arbitrary periods of time, such as a service
performing background music playback.
However, I'm sending info in the Intent that I needed to have redelivered so I'm returning START_REDELIVER_INTENT. Try this (even if you have no need to redeliver any data) to see if it fixes your problem.
Also, I didn't need WakeLock in my implementation. Maybe your implementation needs this though. Have you tried without it?
Edit: Lastly, what kind of device are you using? link

Related

Android Background Location Updates - Different Number of LatLongs in Kitkat And Marshmallow Devices

I am developing an app that gets current latlongs of a device and stores them in a file in a new line. I ran my app on kit kat version 4.4.4 and on marshmallow version 6.0.1. I took both device in my car for testing and took a long ride around the city. I noticed a weird output, the file generated from kit kat had 576 lines means that 576 pair of latlongs were recorded. But in the file generated on marshmallow device had only 250 lines of latlongs. As long as I know, according to the definition of Doze mode introduced in marshmallow, the phone only enters doze mode when the device is stationary. But in my case the device was not stationary because it was in a moving car. I am confused. Can anyone help.
Below is my Background Service Class without file saving code.
public class GPSTrackerService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(getApplicationContext());
mSettingsClient = LocationServices.getSettingsClient(getApplicationContext());
createLocationCallback();
createLocationRequest();
buildLocationSettingsRequest();
new CountDownTimer(9900000,3000){
#Override
public void onTick(long l) {
Log.d("BOSS_DK","On Tick");
}
#Override
public void onFinish() {
}
}.start();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#TargetApi(Build.VERSION_CODES.M)
public void test(){
Intent intent = new Intent();
String packageName = getPackageName();
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm.isIgnoringBatteryOptimizations(packageName))
intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
else {
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
}
startActivity(intent);
}
private LocationRequest mLocationRequest;
private LocationSettingsRequest mLocationSettingsRequest;
private FusedLocationProviderClient mFusedLocationClient;
private LocationCallback mLocationCallback;
private SettingsClient mSettingsClient;
// Start Fused Location services
protected void createLocationRequest() {
// create the locatioon request and set parameters
mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(2000); // will return location after every 5 seconds
mLocationRequest.setFastestInterval(1000); // fastest rate app can handle updates
//mLocationRequest.setSmallestDisplacement(5);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
private void buildLocationSettingsRequest() {
// get current locations settings of user's device
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(mLocationRequest);
builder.addLocationRequest(mLocationRequest);
mLocationSettingsRequest = builder.build();
startLocationUpdates();
}
private void startLocationUpdates() {
// if settings are satisfied initialize location requests
mSettingsClient.checkLocationSettings(mLocationSettingsRequest).addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
//locUpdates = true;
// All location settings are satisfied.
//noinspection MissingPermission - this comment needs to stay here to stop inspection on next line
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
}
})
// if settings need to be changed prompt user
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
e.printStackTrace();
}
});
}
// stop location updates
private void stopLocationUpdates() {
//locUpdates = false;
mFusedLocationClient.removeLocationUpdates(mLocationCallback).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
}
});
}
private void createLocationCallback() {
mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
List<Location> locations = locationResult.getLocations();
/*if(locationResult.getLastLocation().hasAccuracy()) {
setLatLong(locationResult.getLastLocation());
}*/
for(Location location : locations){
setLatLong(location);
}
}
};
}
// Set new latitude and longitude based on location results
public void setLatLong(Location location) {
Log.d("BOSS_DK",String.valueOf(location.getLatitude())+","+String.valueOf(location.getLongitude()));
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("BOSS_DK","service destroyed");
}
}
I guess this is due to Background Location Limitation. States:
Location retrieval behaviour is particularly important to keep in mind if your app relies on real-time alerts or motion detection while running in the background.
The system distinguishes between foreground and background apps. An app is considered to be in the foreground if any of the following is true:
It has a visible activity, whether the activity is started or paused.
It has a foreground service.
Another foreground app is connected to the app, either by binding to one of its services or by making use of one of its content providers. For example, if a foreground app binds to any of the following components within another app, that other app is considered to be in the foreground:
Input method editor (IME)
Wallpaper service
Notification listener
Voice or text service
If none of those conditions is true, the app is considered to be in the background.

Automatically display location google android

I am struggling with a problem to display my reverse geocoding results automatically. It works fine when I click button to get location, but I want it to simply display the location automatically when the app is loaded.
My code is in a Java class called geocoding, eventually i want to display this code on a marker on my map, which i have already created.
but this thread is to eliminate the button and display location as son as map loads.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); // uses layout from mainactivity
mResultReceiver = new AddressResultReceiver(new Handler());
mLocationAddressTextView = (TextView) findViewById(R.id.location_address_view);
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
mFetchAddressButton = (Button) findViewById(R.id.fetch_address_button);
// Set defaults, then update using values stored in the Bundle.
mAddressRequested = false;
mAddressOutput = "";
updateValuesFromBundle(savedInstanceState);
updateUIWidgets();
buildGoogleApiClient();
}
public void buttonOnClick(View view) { // this links the maps activity via the XML layout file
startActivity(new Intent(Geocode.this, MapsActivity.class));
}
/**
* Updates fields based on data stored in the bundle.
*/
private void updateValuesFromBundle(Bundle savedInstanceState) {
if (savedInstanceState != null) {
// Check savedInstanceState to see if the address was previously requested.
if (savedInstanceState.keySet().contains(ADDRESS_REQUESTED_KEY)) {
mAddressRequested = savedInstanceState.getBoolean(ADDRESS_REQUESTED_KEY);
}
// Check savedInstanceState to see if the location address string was previously found
// and stored in the Bundle. If it was found, display the address string in the UI.
if (savedInstanceState.keySet().contains(LOCATION_ADDRESS_KEY)) {
mAddressOutput = savedInstanceState.getString(LOCATION_ADDRESS_KEY);
displayAddressOutput();
}
}
}
/**
* Builds a GoogleApiClient. Uses {#code #addApi} to request the LocationServices API.
*/
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
public void fetchAddressButtonHandler(View view) {
// We only start the service to fetch the address if GoogleApiClient is connected.
if (mGoogleApiClient.isConnected() && mLastLocation != null) {
startIntentService();
}
mAddressRequested = true;
updateUIWidgets();
}
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
/**
* Runs when a GoogleApiClient object successfully connects.
*/
#Override
public void onConnected(Bundle connectionHint) {
// Gets the best and most recent location currently available, which may be null
// in rare cases when a location is not available.
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
return;
}
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mLastLocation != null) {
// Determine whether a Geocoder is available.
if (!Geocoder.isPresent()) {
Toast.makeText(this, R.string.no_geocoder_available, Toast.LENGTH_LONG).show();
return;
}
if (mAddressRequested) {
startIntentService();
}
}
}
/**
* Creates an intent, adds location data to it as an extra, and starts the intent service for
* fetching an address.
*/
protected void startIntentService() {
// Create an intent for passing to the intent service responsible for fetching the address.
Intent intent = new Intent(this, FetchAddressIntentService.class);
// Pass the result receiver as an extra to the service.
intent.putExtra(Constants.RECEIVER, mResultReceiver);
// Pass the location data as an extra to the service.
intent.putExtra(Constants.LOCATION_DATA_EXTRA, mLastLocation);
startService(intent);
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
}
#Override
public void onConnectionSuspended(int cause) {
// The connection to Google Play services was lost for some reason. We call connect() to
// attempt to re-establish the connection.
Log.i(TAG, "Connection suspended");
mGoogleApiClient.connect();
}
/**
* Updates the address in the UI.
*/
protected void displayAddressOutput() {
mLocationAddressTextView.setText(mAddressOutput);
}
/**
* Toggles the visibility of the progress bar. Enables or disables the Fetch Address button.
*/
private void updateUIWidgets() {
if (mAddressRequested) {
mProgressBar.setVisibility(ProgressBar.VISIBLE);
mFetchAddressButton.setEnabled(false);
} else {
mProgressBar.setVisibility(ProgressBar.GONE);
mFetchAddressButton.setEnabled(true);
}
}
/**
* Shows a toast with the given text.
*/
protected void showToast(String text) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save whether the address has been requested.
savedInstanceState.putBoolean(ADDRESS_REQUESTED_KEY, mAddressRequested);
// Save the address string.
savedInstanceState.putString(LOCATION_ADDRESS_KEY, mAddressOutput);
super.onSaveInstanceState(savedInstanceState);
}
/**
* Receiver for data sent from FetchAddressIntentService.
*/
class AddressResultReceiver extends ResultReceiver {
public AddressResultReceiver(Handler handler) {
super(handler);
}
/**
* Receives data sent from FetchAddressIntentService and updates the UI in MainActivity.
*/
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
// Display the address string or an error message sent from the intent service.
mAddressOutput = resultData.getString(Constants.RESULT_DATA_KEY);
displayAddressOutput();
// Show a toast message if an address was found.
if (resultCode == Constants.SUCCESS_RESULT) {
showToast(getString(R.string.address_found));
}
// Reset. Enable the Fetch Address button and stop showing the progress bar.
mAddressRequested = false;
updateUIWidgets();
}
}
}
set mAdressRequested from False to True,
so in OnConnected, startIntentService can be called
// Set defaults, then update using values stored in the Bundle.
mAddressRequested = true;
mAddressOutput = "";
updateValuesFromBundle(savedInstanceState);

'double android.location.Location.getLatitude()' on a null object reference ParseGeoPoints

I want to query parse to return list of names stored on the Parse Cloud. I am implemented geoLocation and I am using getLatitude and getLongitutude to ParseGeoPoint to get the list of names.
public class TakePhotoActivity extends BaseActivity implements RevealBackgroundView.OnStateChangeListener, LocationListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
CameraHostProvider {
public static final String ARG_REVEAL_START_LOCATION = "reveal_start_location";
private static final Interpolator ACCELERATE_INTERPOLATOR = new AccelerateInterpolator();
private static final Interpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();
private static final int STATE_TAKE_PHOTO = 0;
private static final int STATE_SETUP_PHOTO = 1;
/*
* Define a request code to send to Google Play services This code is returned in
* Activity.onActivityResult
*/
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
/*
* Constants for location update parameters
*/
// Milliseconds per second
private static final int MILLISECONDS_PER_SECOND = 1000;
// The update interval
private static final int UPDATE_INTERVAL_IN_SECONDS = 5;
// A fast interval ceiling
private static final int FAST_CEILING_IN_SECONDS = 1;
// Update interval in milliseconds
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = MILLISECONDS_PER_SECOND
* UPDATE_INTERVAL_IN_SECONDS;
// A fast ceiling of update intervals, used when the app is visible
private static final long FAST_INTERVAL_CEILING_IN_MILLISECONDS = MILLISECONDS_PER_SECOND
* FAST_CEILING_IN_SECONDS;
#Bind(R.id.vRevealBackground)
RevealBackgroundView vRevealBackground;
#Bind(R.id.vPhotoRoot)
View vTakePhotoRoot;
#Bind(R.id.vShutter)
View vShutter;
#Bind(R.id.ivTakenPhoto)
ImageView ivTakenPhoto;
#Bind(R.id.vUpperPanel)
ViewSwitcher vUpperPanel;
#Bind(R.id.vLowerPanel)
ViewSwitcher vLowerPanel;
#Bind(R.id.cameraView)
CameraView cameraView;
#Bind(R.id.rvFilters)
RecyclerView rvFilters;
#Bind(R.id.btnTakePhoto)
Button btnTakePhoto;
private float radius;
private float lastRadius;
private boolean pendingIntro;
private int currentState;
private Location lastLocation;
private Location currentLocation;
// A request to connect to Location Services
private LocationRequest locationRequest;
// Stores the current instantiation of the location client in this object
private GoogleApiClient locationClient;
private File photoPath;
public static void startCameraFromLocation(int[] startingLocation, Activity startingActivity) {
Intent intent = new Intent(startingActivity, TakePhotoActivity.class);
intent.putExtra(ARG_REVEAL_START_LOCATION, startingLocation);
startingActivity.startActivity(intent);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_take_photo);
updateStatusBarColor();
updateState(STATE_TAKE_PHOTO);
setupRevealBackground(savedInstanceState);
setupPhotoFilters();
radius = InstaMaterialApplication.getSearchDistance();
lastRadius = radius;
// Create a new global location parameters object
locationRequest = LocationRequest.create();
// Set the update interval
locationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
// Use high accuracy
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the interval ceiling to one minute
locationRequest.setFastestInterval(FAST_INTERVAL_CEILING_IN_MILLISECONDS);
// Create a new location client, using the enclosing class to handle callbacks.
locationClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
vUpperPanel.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
vUpperPanel.getViewTreeObserver().removeOnPreDrawListener(this);
pendingIntro = true;
vUpperPanel.setTranslationY(-vUpperPanel.getHeight());
vLowerPanel.setTranslationY(vLowerPanel.getHeight());
return true;
}
});
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void updateStatusBarColor() {
if (Utils.isAndroid5()) {
getWindow().setStatusBarColor(0xff111111);
}
}
private void setupRevealBackground(Bundle savedInstanceState) {
vRevealBackground.setFillPaintColor(0xFF16181a);
vRevealBackground.setOnStateChangeListener(this);
if (savedInstanceState == null) {
final int[] startingLocation = getIntent().getIntArrayExtra(ARG_REVEAL_START_LOCATION);
vRevealBackground.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
vRevealBackground.getViewTreeObserver().removeOnPreDrawListener(this);
vRevealBackground.startFromLocation(startingLocation);
return true;
}
});
} else {
vRevealBackground.setToFinishedFrame();
}
}
FiltersQueryAdapter mainAdapter = new FiltersQueryAdapter(this, PhotoFiltersAdapter.class
, new ParseRecyclerQueryAdapter.QueryFactory() {
public ParseQuery create() {
Location myLoc = (currentLocation == null) ? lastLocation : currentLocation;
ParseQuery query = ParseQuery.getQuery("PlaceFilters");
//query.include("user");
query.orderByAscending("GeoArea");
query.whereWithinKilometers("GeoArea", geoPointFromLocation(myLoc), radius);
query.setLimit(6);
return query;
}
});
private void setupPhotoFilters() {
rvFilters.setHasFixedSize(true);
rvFilters.setAdapter(mainAdapter);
rvFilters.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
}
#Override
protected void onResume() {
super.onResume();
cameraView.onResume();
// Get the latest search distance preference
radius = InstaMaterialApplication.getSearchDistance();
// Checks the last saved location to show cached data if it's available
if (lastLocation != null) {
// If the search distance preference has been changed, move
// map to new bounds.
if (lastRadius != radius) {
// Save the current radius
lastRadius = radius;
doListQuery();
}
}
}
#Override
protected void onPause() {
super.onPause();
cameraView.onPause();
}
/*
* Called when the Activity is no longer visible at all. Stop updates and disconnect.
*/
#Override
public void onStop() {
// If the client is connected
if (locationClient.isConnected()) {
stopPeriodicUpdates();
}
// After disconnect() is called, the client is considered "dead".
locationClient.disconnect();
super.onStop();
}
/*
* Called when the Activity is restarted, even before it becomes visible.
*/
#Override
public void onStart() {
super.onStart();
// Connect to the location services client
locationClient.connect();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
// Choose what to do based on the request code
switch (requestCode) {
// If the request code matches the code sent in onConnectionFailed
case CONNECTION_FAILURE_RESOLUTION_REQUEST:
switch (resultCode) {
// If Google Play services resolved the problem
case Activity.RESULT_OK:
if (InstaMaterialApplication.APPDEBUG) {
// Log the result
Log.d(InstaMaterialApplication.APPTAG, "Connected to Google Play services");
}
break;
// If any other result was returned by Google Play services
default:
if (InstaMaterialApplication.APPDEBUG) {
// Log the result
Log.d(InstaMaterialApplication.APPTAG, "Could not connect to Google Play services");
}
break;
}
// If any other request code was received
default:
if (InstaMaterialApplication.APPDEBUG) {
// Report that this Activity received an unknown requestCode
Log.d(InstaMaterialApplication.APPTAG, "Unknown request code received for the activity");
}
break;
}
}
#OnClick(R.id.btnTakePhoto)
public void onTakePhotoClick() {
btnTakePhoto.setEnabled(false);
cameraView.takePicture(true, true);
animateShutter();
}
#OnClick(R.id.btnAccept)
public void onAcceptClick() {
PublishActivity.openWithPhotoUri(this, Uri.fromFile(photoPath));
}
/*
* Verify that Google Play services is available before making a request.
*
* #return true if Google Play services is available, otherwise false
*/
private boolean servicesConnected() {
// Check that Google Play services is available
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
// If Google Play services is available
if (ConnectionResult.SUCCESS == resultCode) {
if (InstaMaterialApplication.APPDEBUG) {
// In debug mode, log the status
Log.d(InstaMaterialApplication.APPTAG, "Google play services available");
}
// Continue
return true;
// Google Play services was not available for some reason
} else {
// Display an error dialog
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(resultCode, this, 0);
if (dialog != null) {
ErrorDialogFragment errorFragment = new ErrorDialogFragment();
errorFragment.setDialog(dialog);
errorFragment.show(getSupportFragmentManager(), InstaMaterialApplication.APPTAG);
}
return false;
}
}
/*
* Called by Location Services when the request to connect the client finishes successfully. At
* this point, you can request the current location or start periodic updates
*/
public void onConnected(Bundle bundle) {
if (InstaMaterialApplication.APPDEBUG) {
Log.d("Location Connected", InstaMaterialApplication.APPTAG);
}
currentLocation = getLocation();
startPeriodicUpdates();
}
/*
* Called by Location Services if the connection to the location client drops because of an error.
*/
public void onDisconnected() {
if (InstaMaterialApplication.APPDEBUG) {
Log.d("Location Disconnected", InstaMaterialApplication.APPTAG);
}
}
#Override
public void onConnectionSuspended(int i) {
Log.i(InstaMaterialApplication.APPTAG, "GoogleApiClient connection has been suspend");
}
/*
* Called by Location Services if the attempt to Location Services fails.
*/
public void onConnectionFailed(ConnectionResult connectionResult) {
// Google Play services can resolve some errors it detects. If the error has a resolution, try
// sending an Intent to start a Google Play services activity that can resolve error.
if (connectionResult.hasResolution()) {
try {
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
if (InstaMaterialApplication.APPDEBUG) {
// Thrown if Google Play services canceled the original PendingIntent
Log.d(InstaMaterialApplication.APPTAG, "An error occurred when connecting to location services.", e);
}
}
} else {
// If no resolution is available, display a dialog to the user with the error.
showErrorDialog(connectionResult.getErrorCode());
}
}
/*
* Report location updates to the UI.
*/
public void onLocationChanged(Location location) {
currentLocation = location;
if (lastLocation != null
&& geoPointFromLocation(location)
.distanceInKilometersTo(geoPointFromLocation(lastLocation)) < 0.01) {
// If the location hasn't changed by more than 10 meters, ignore it.
return;
}
lastLocation = location;
// Update map radius indicator
doListQuery();
}
/*
* In response to a request to start updates, send a request to Location Services
*/
private void startPeriodicUpdates() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(
locationClient, locationRequest, this);
}
/*
* In response to a request to stop updates, send a request to Location Services
*/
private void stopPeriodicUpdates() {
locationClient.disconnect();
}
/*
* Get the current location
*/
private Location getLocation() {
// If Google Play Services is available
if (servicesConnected()) {
// Get the current location
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
}
return LocationServices.FusedLocationApi.getLastLocation(locationClient);
} else {
return null;
}
}
/*
* Set up a query to update the list view
*/
private void doListQuery() {
Location myLoc = (currentLocation == null) ? lastLocation : currentLocation;
// If location info is available, load the data
if (myLoc != null) {
// Refreshes the list view with new data based
// usually on updated location data.
// mainAdapter.;
}
}
/*
* Helper method to get the Parse GEO point representation of a location
*/
private ParseGeoPoint geoPointFromLocation(Location loc) {
return new ParseGeoPoint(loc.getLatitude(), loc.getLongitude());
}
/*
* Show a dialog returned by Google Play services for the connection error code
*/
private void showErrorDialog(int errorCode) {
// Get the error dialog from Google Play services
Dialog errorDialog =
GooglePlayServicesUtil.getErrorDialog(errorCode, this,
CONNECTION_FAILURE_RESOLUTION_REQUEST);
// If Google Play services can provide an error dialog
if (errorDialog != null) {
// Create a new DialogFragment in which to show the error dialog
ErrorDialogFragment errorFragment = new ErrorDialogFragment();
// Set the dialog in the DialogFragment
errorFragment.setDialog(errorDialog);
// Show the error dialog in the DialogFragment
errorFragment.show(getSupportFragmentManager(), InstaMaterialApplication.APPTAG);
}
}
/*
* Define a DialogFragment to display the error dialog generated in showErrorDialog.
*/
public static class ErrorDialogFragment extends DialogFragment {
// Global field to contain the error dialog
private Dialog mDialog;
/**
* Default constructor. Sets the dialog field to null
*/
public ErrorDialogFragment() {
super();
mDialog = null;
}
/*
* Set the dialog to display
*
* #param dialog An error dialog
*/
public void setDialog(Dialog dialog) {
mDialog = dialog;
}
/*
* This method must return a Dialog to the DialogFragment.
*/
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return mDialog;
}
}
private void animateShutter() {
vShutter.setVisibility(View.VISIBLE);
vShutter.setAlpha(0.f);
ObjectAnimator alphaInAnim = ObjectAnimator.ofFloat(vShutter, "alpha", 0f, 0.8f);
alphaInAnim.setDuration(100);
alphaInAnim.setStartDelay(100);
alphaInAnim.setInterpolator(ACCELERATE_INTERPOLATOR);
ObjectAnimator alphaOutAnim = ObjectAnimator.ofFloat(vShutter, "alpha", 0.8f, 0f);
alphaOutAnim.setDuration(200);
alphaOutAnim.setInterpolator(DECELERATE_INTERPOLATOR);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(alphaInAnim, alphaOutAnim);
animatorSet.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
vShutter.setVisibility(View.GONE);
}
});
animatorSet.start();
}
#Override
public void onStateChange(int state) {
if (RevealBackgroundView.STATE_FINISHED == state) {
vTakePhotoRoot.setVisibility(View.VISIBLE);
if (pendingIntro) {
startIntroAnimation();
}
} else {
vTakePhotoRoot.setVisibility(View.INVISIBLE);
}
}
private void startIntroAnimation() {
vUpperPanel.animate().translationY(0).setDuration(400).setInterpolator(DECELERATE_INTERPOLATOR);
vLowerPanel.animate().translationY(0).setDuration(400).setInterpolator(DECELERATE_INTERPOLATOR).start();
}
#Override
public CameraHost getCameraHost() {
return new MyCameraHost(this);
}
class MyCameraHost extends SimpleCameraHost {
private Camera.Size previewSize;
public MyCameraHost(Context ctxt) {
super(ctxt);
}
#Override
public boolean useFullBleedPreview() {
return true;
}
#Override
public Camera.Size getPictureSize(PictureTransaction xact, Camera.Parameters parameters) {
return previewSize;
}
#Override
public Camera.Parameters adjustPreviewParameters(Camera.Parameters parameters) {
Camera.Parameters parameters1 = super.adjustPreviewParameters(parameters);
previewSize = parameters1.getPreviewSize();
return parameters1;
}
#Override
public void saveImage(PictureTransaction xact, final Bitmap bitmap) {
runOnUiThread(new Runnable() {
#Override
public void run() {
showTakenPicture(bitmap);
}
});
}
#Override
public void saveImage(PictureTransaction xact, byte[] image) {
super.saveImage(xact, image);
photoPath = getPhotoPath();
}
}
private void showTakenPicture(Bitmap bitmap) {
vUpperPanel.showNext();
vLowerPanel.showNext();
ivTakenPhoto.setImageBitmap(bitmap);
updateState(STATE_SETUP_PHOTO);
}
#Override
public void onBackPressed() {
if (currentState == STATE_SETUP_PHOTO) {
btnTakePhoto.setEnabled(true);
vUpperPanel.showNext();
vLowerPanel.showNext();
updateState(STATE_TAKE_PHOTO);
} else {
super.onBackPressed();
}
}
private void updateState(int state) {
currentState = state;
if (currentState == STATE_TAKE_PHOTO) {
vUpperPanel.setInAnimation(this, R.anim.slide_in_from_right);
vLowerPanel.setInAnimation(this, R.anim.slide_in_from_right);
vUpperPanel.setOutAnimation(this, R.anim.slide_out_to_left);
vLowerPanel.setOutAnimation(this, R.anim.slide_out_to_left);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
ivTakenPhoto.setVisibility(View.GONE);
}
}, 400);
} else if (currentState == STATE_SETUP_PHOTO) {
vUpperPanel.setInAnimation(this, R.anim.slide_in_from_left);
vLowerPanel.setInAnimation(this, R.anim.slide_in_from_left);
vUpperPanel.setOutAnimation(this, R.anim.slide_out_to_right);
vLowerPanel.setOutAnimation(this, R.anim.slide_out_to_right);
ivTakenPhoto.setVisibility(View.VISIBLE);
}
}
}
Here is my Logcat:
02-16 17:32:40.700 22343-22343/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.google.peep, PID: 22343
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.google.peep/com.google.peep.activity.TakePhotoActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2484)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2544)
at android.app.ActivityThread.access$900(ActivityThread.java:150)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1394)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:168)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:687)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference
at com.google.peep.activity.TakePhotoActivity.geoPointFromLocation(TakePhotoActivity.java:501)
at com.google.peep.activity.TakePhotoActivity.access$300(TakePhotoActivity.java:66)
at com.google.peep.activity.TakePhotoActivity$3.create(TakePhotoActivity.java:223)
at com.javon.parserecyclerviewadapter.ParseRecyclerQueryAdapter.loadParseData(ParseRecyclerQueryAdapter.java:96)
at com.javon.parserecyclerviewadapter.ParseRecyclerQueryAdapter.registerAdapterDataObserver(ParseRecyclerQueryAdapter.java:176)
at android.support.v7.widget.RecyclerView.setAdapterInternal(RecyclerView.java:886)
at android.support.v7.widget.RecyclerView.setAdapter(RecyclerView.java:847)
at com.google.peep.activity.TakePhotoActivity.setupPhotoFilters(TakePhotoActivity.java:232)
at com.google.peep.activity.TakePhotoActivity.onCreate(TakePhotoActivity.java:152)
Your getlocation is before the google api client actually connects,pass setup photofilters in onConnected and it will run.Tatasthu!

Remove Geofence Using Reset Button

How can i remove the Geofence? everytime i click the reset button it shows the following error-
Caused by: java.lang.IllegalStateException: GoogleApiClient is not connected yet.
Here is my code-
public class GeofenceStore implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<Status>, LocationListener {
private Context mContext;
/**
* Google API client object.
*/
private GoogleApiClient mGoogleApiClient;
/**
* Geofencing PendingIntent
*/
private PendingIntent mPendingIntent;
/**
* List of geofences to monitor.
*/
private ArrayList<Geofence> mGeofences;
/**
* Geofence request.
*/
private GeofencingRequest mGeofencingRequest;
/**
* Location Request object.
*/
private LocationRequest mLocationRequest;
public GeofenceStore(Context context, ArrayList<Geofence> geofences) {
mContext = context;
mGeofences = new ArrayList<Geofence>(geofences);
mPendingIntent = null;
// Build a new GoogleApiClient, specify that we want to use LocationServices
// by adding the API to the client, specify the connection callbacks are in
// this class as well as the OnConnectionFailed method.
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
Log.i("APi is :", "+" + mGoogleApiClient);
mLocationRequest = new LocationRequest();
// We want a location update every 10 seconds.
mLocationRequest.setInterval(10000);
// We want the location to be as accurate as possible.
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mGoogleApiClient.connect();
}
#Override
public void onConnected(Bundle bundle) {
// We're connected, now we need to create a GeofencingRequest with
// the geofences we have stored.
mGeofencingRequest = new GeofencingRequest.Builder().addGeofences(
mGeofences).build();
mPendingIntent = createRequestPendingIntent();
// This is for debugging only and does not affect
// geofencing.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ActivityCompat.checkSelfPermission(mContext,Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext,Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
GeofenceStore.this.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 100);
// public void requestPermissions(#NonNull String[] permissions, int requestCode)
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for Activity#requestPermissions for more details.
return;
}
}
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
// Submitting the request to monitor geofences.
PendingResult<Status> pendingResult = LocationServices.GeofencingApi
.addGeofences(mGoogleApiClient, mGeofencingRequest,
mPendingIntent);
// Set the result callbacks listener to this class.
pendingResult.setResultCallback(this);
}
private void requestPermissions(String[] strings, int i) {
switch(i)
{
case 100: {
{
Log.i("thanks","asdm");
}
}
}
}
public void removeGeofence(){
LocationServices.GeofencingApi.removeGeofences(
mGoogleApiClient,
// This is the same pending intent that was used in addGeofences().
mPendingIntent
).setResultCallback(this); // Result processed in onResult().
}
private void requestPermissions(int requestCode,String[] permissions, int[] grantResults) {
switch (requestCode) {
case 100: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(mContext, "Thanks for the permission", Toast.LENGTH_LONG).show();
// permission was granted, yay! do the
// calendar task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
Toast.makeText(mContext, "You did not allow to access your current location", Toast.LENGTH_LONG).show();
}
}
// other 'switch' lines to check for other
// permissions this app might request
}
}
/**
* This creates a PendingIntent that is to be fired when geofence transitions
* take place. In this instance, we are using an IntentService to handle the
* transitions.
*
* #return A PendingIntent that will handle geofence transitions.
*/
private PendingIntent createRequestPendingIntent() {
if (mPendingIntent == null) {
Log.v("HERE", "Creating PendingIntent");
Intent intent = new Intent(mContext, GeofenceIntentService.class);
Log.i("another class called",""+intent);
mPendingIntent = PendingIntent.getService(mContext, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
try {
mPendingIntent.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
}
return mPendingIntent;
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onLocationChanged(Location location) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
public void onProviderEnabled(String provider) {
}
public void onProviderDisabled(String provider) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.v("THE CONNECTION HAS", "failed.");
}
public void onSuccess(AsyncTask.Status status) {
}
public void onFailure(Status status) {
}
#Override
public void onResult(Status result) {
if (result.isSuccess()) {
Log.v("THE RESULT IS", "Success!");
} else if (result.hasResolution()) {
// TODO Handle resolution
} else if (result.isCanceled()) {
Log.v("THE RESULT IS", "Canceled");
} else if (result.isInterrupted()) {
Log.v("THE RESULT IS", "Interrupted");
} else {
}
}
}
and here is the function to call from my maps activity, i have used a reset button to reset the geofence added.Pendind intent can be found in the above mentioned code. i want to know what is the problem with it?
The button is-
public void Reset(View view){
db.execSQL("DELETE FROM Coordinates");
//delete all rows in a table
request=request-1;
GeofenceStore mgeofencestore=new GeofenceStore(this,mGeofences);
mgeofencestore.removeGeofence();
db.close();
Toast.makeText(this,"The Data was reset,Please click on 'Add Geofence' to add more Geofence",Toast.LENGTH_LONG).show();
}
You're creating a new GoogleAPIClient every time create a new GeofenceStore object. Since you call removeGeofences() immediately after, the GoogleAPIClient never has a chance to connect, and throws the error you are seeing. Either place a copy of the GeofenceStore object you initially make in the calling class, or create a static instance method to get the current object and avoid recreating it.

FusedLocationApi Background Location service stops receiving updates randomly

i'm trying to use FusedLocationApi with pending intent to get period location updates so i can send the data to some server for processing. Everything works. However, there are some instances where the broadcast just stops receiving. I would need to restart the service again in order for it to continue.
I already have the service onStartCommand to return START_STICKY so even if the app is killed it should start the service again. Furthermore, I also added a Boot Completed Intent Receiver so if the phone died and user restarted phone it would restart my service.
So it seems everything is fine and working but just at some point, everything just stops. I did notice a few times that when it does stop working, the last location i received was NULL (i log every location update and error messages throughout my project).
Any ideas why location services just stops working?
P.S. there is no connection failure because i put a message and hook into that function and it's not being called. And it's not internet failure either as i log that as well. Once internet is restored it would continue as normal/expected.
Thanks.
This is the main activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayShowHomeEnabled(false);
actionBar.setDisplayShowTitleEnabled(false);
if (findViewById(android.R.id.home) != null) {
findViewById(android.R.id.home).setVisibility(View.GONE);
}
LayoutInflater inflator = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflator.inflate(R.layout.header_logo, null);
ActionBar.LayoutParams params = new ActionBar.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT, Gravity.CENTER);
actionBar.setDisplayShowCustomEnabled(true);
actionBar.setCustomView(view, params);
}
setContentView(R.layout.activity_main);
TextView textView = (TextView) findViewById(R.id.status_text);
// init preferences and status handler
MyStatusHandler.init(getApplicationContext(), textView);
// init web service call class
...;
// check for location services
if (!isLocationEnabled(getApplicationContext())){
String msg = "Location services not turned on";
MyStatusHandler.setStatusText(msg);
}
}
public static boolean isLocationEnabled(Context context) {
int locationMode = 0;
String locationProviders;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
try {
locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
return locationMode != Settings.Secure.LOCATION_MODE_OFF;
}else{
locationProviders = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
return !TextUtils.isEmpty(locationProviders);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
// create new intent activity for the settings page
Intent i = new Intent(this, MySettingsActivity.class);
startActivity(i);
return true;
}
else if (id == R.id.action_about){
// 1. Instantiate an AlertDialog.Builder with its constructor
AlertDialog.Builder builder = new AlertDialog.Builder(this);
// 2. Chain together various setter methods to set the dialog characteristics
if (Constants.DEBUG_BUILD == true) {
builder.setMessage("v." + MyStatusHandler.getReleaseVersionNum() + " dev Build: " + MyStatusHandler.getDevVersionNum())
.setTitle("About")
.setCancelable(false)
.setPositiveButton("OK", null);
}
else{
builder.setMessage("v." + MyStatusHandler.getReleaseVersionNum())
.setTitle("About")
.setCancelable(false)
.setPositiveButton("OK", null);
}
// 3. Get the AlertDialog from create()
AlertDialog dialog = builder.create();
// show it
dialog.show();
return true;
}
return super.onOptionsItemSelected(item);
}
// check email entered
public boolean isSettingsEntered(){
boolean result = true;
if (MyStatusHandler.getEmailText().equals("") || MyStatusHandler.getPasswordText().equals("")){
// 1. Instantiate an AlertDialog.Builder with its constructor
AlertDialog.Builder builder = new AlertDialog.Builder(this);
// 2. Chain together various setter methods to set the dialog characteristics
builder.setMessage("Please ensure both email and password are entered in settings")
.setTitle("Email and/or Password not set")
.setCancelable(false)
.setPositiveButton("OK",null);
// 3. Get the AlertDialog from create()
AlertDialog dialog = builder.create();
// show it
dialog.show();
result = false;
}
return result;
}
/** Called when the user clicks the Opt in button */
public void startService(View view) {
// Do something in response to button
if (isSettingsEntered() && isLocationEnabled(getApplicationContext())) {
// send opt in to web service
...;
// start service
startService(new Intent(this, BackgroundLocationService.class));
// update status text
String msg = "Connecting ...";
MyStatusHandler.setStatusText(msg);
}
}
/** Called when the user clicks the Opt out button */
public void stopService(View view) {
// Do something in response to button
if (isSettingsEntered() && isLocationEnabled(getApplicationContext())) {
// send OptOut to web service
...;
// update status text
String msg = "Connecting ...";
MyStatusHandler.setStatusText(msg);
}
}
public static void ...(boolean isOptIn, Location location, boolean sendOptIn){
if (sendOptIn)
{
// send opt in via async task
}
else{
// send location via async task
}
}
// Handle results returned to the FragmentActivity by Google Play services
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Decide what to do based on the original request code
switch (requestCode) {
case Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST :
// log the error
MyStatusHandler.logDataToFile("Connection Failure Resolution Request - Result Code: "+String.valueOf(resultCode));
// If the result code is Activity.RESULT_OK, try to connect again
switch (resultCode) {
case Activity.RESULT_OK :
// Try the request again
MyStatusHandler.logDataToFile("Attempting to re-start service");
// start service
startService(new Intent(this, BackgroundLocationService.class));
break;
}
}
}
}
Here is the background service:
public class BackgroundLocationService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
public static final String TAG = BackgroundLocationService.class.getSimpleName();
private GoogleApiClient mGoogleApiClient;
private boolean mInProgress;
private LocationRequest mLocationRequest;
public void onCreate(){
super.onCreate();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
#Override
public int onStartCommand (Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if(mGoogleApiClient.isConnected() || mInProgress)
return START_STICKY;
if(!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() && !mInProgress) {
mInProgress = true;
mGoogleApiClient.connect();
}
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onConnected(Bundle bundle) {
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setFastestInterval(Constants.FASTEST_INTERVAL)
.setInterval(Constants.UPDATE_INTERVAL);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
new Intent(this, MyLocationHandler.class),
PendingIntent.FLAG_CANCEL_CURRENT);
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, pendingIntent);
}
else{
MyStatusHandler.setStatusText("Google Client Failed");
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
mInProgress = false;
if (connectionResult.hasResolution()) {
try {
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(null, Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST);
// * Thrown if Google Play services canceled the original
// * PendingIntent
} catch (IntentSender.SendIntentException e) {
// Log the error
e.printStackTrace();
}
} else {
//* If no resolution is available, display a dialog to the
// * user with the error.
Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
MyStatusHandler.setStatusText("Location services connection failed with code " + connectionResult.getErrorCode());
}
}
#Override
public void onDestroy(){
mInProgress = false;
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
super.onDestroy();
}
}
Here is the broadcast receiver:
public class MyLocationHandler extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Location location = intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED);
if (location != null && MyStatusHandler.getOptInStatus()) {
// debug messages
String msg = Double.toString(location.getLatitude()) + "," +
Double.toString(location.getLongitude());
Log.d("debug", msg);
// log location to file
MyStatusHandler.logDataToFile("Location: "+msg);
// send Location to web service
MainActivity....(MyStatusHandler.getOptInStatus(), location, false);
}
if (location == null){
MyStatusHandler.logDataToFile("Location == NULL!");
}
}
}
I have set the interval to 5minutes and Fast interval to 2minutes.
NOTE: i removed some function calls and code for the web service operations
Everything works and i get updates as expected but at some point in time, the broadcast receiver doesn't get anything. When i check the logs, OptInStatus doesn't change and the last location broadcast i received was NULL.
The other parts of my code to call the web service and handle the status messages doesn't touch the service or location requests.

Categories

Resources